2023年2月

Winform 里面的TreeView是一种常见的、功能强大的控件,一般的使用大家可能都是比较熟悉的了,估计我们大多数做定位节点的时候,一般都是采用循环查找的方法。如下面的方法所示


foreach
(TreeNode node
in

this
.TreeView1.Nodes)
{

if
(node.Text
==

"
要找的节点名称
"
)
{

return
node;
}

return

null
;
}

另外还有一种方法是使用
TreeNode.FromHandle方法来快速定位节点,为了说明如何使用,我们假设有这么一个场景,有一个集团,集团里面有很多公司,每个公司又有一些子公司,

我们需要在每个子公司下面增加一些设备节点或者人员节点。那我们应该如何处理这些节点的显示和定位呢?

首先我们在添加集团这些公司及子公司节点的时候,分别记录这些公司及子公司的树节点信息,放到内存列表中。代码如下所示。

TreeView treeView
=

this
.TreeView1;

treeView.Nodes.Clear();

foreach
(
string
key
in
groupList.Keys)

{

TreeNode node
=
treeView.Nodes.Add(key, key,
0
);

if
(
!
companyHandleDict.ContainsKey(key))

{

companyHandleDict.Add(key, node.Handle);

}

}


foreach
(
string
key
in
groupList.Keys)

{

foreach
(
string
subKey
in
groupList[key].Keys)

{

TreeNode node
=
TreeNode.FromHandle(treeView, companyHandleDict[key]);

if
(node
!=

null
)

{

TreeNode tempNode
=
node.Nodes.Add(subKey, subKey,
0
);

if
(
!
subCompanyHandleDict.ContainsKey(key
+
subKey))

{

subCompanyHandleDict.Add(key
+
subKey, tempNode.Handle);

}

}

}

}

记录了这些TreeNode的Handle之后,我们如果要在这些节点上添加子节点的时候,就可以快速定位了。代码如下所示。


foreach
(Taxi taxi
in
taxiDcit.Values)
{

string
key
=
taxi.MyInfo.Corporation
+
taxi.MyInfo.Filialy;
TreeNode node

=
TreeNode.FromHandle(treeView, subCompanyHandleDict[key]);

if
(node
!=

null
)
{
TreeNode subNode

=

new
TreeNode(taxi.MyBrand,
1
,
2
);
subNode.Tag

=

"
vehicle
"
;
node.Nodes.Add(subNode);
}

}

以上只是一个小技巧处理节点的定位,希望对大家有帮助。

ActiveReport 是.net下的一个出色的报表开发程序,虽然和水晶报表相比,名气不那么大,甚至有很多人不知道它的存在,但是并不妨碍它在.net报表开发中的出色表现,本文主要介绍下其中文化的操作。 ActiveReport 目前最新版本是3.0,默认运行的例子是英文的,所以如果要在其报表浏览器中将界面变为中文的,有两种方法可以实现。

第一种是,在报表浏览器实例化的时候,把里面的对象的提示和文本变化,实现中文化的操作。修改代码如下所示。


this
.arvMain.Toolbar.Tools[
0
].ToolTip
=

"
各页目录
"
;

this
.arvMain.Toolbar.Tools[
2
].Caption
=

"
打印
"
;

this
.arvMain.Toolbar.Tools[
2
].ToolTip
=

"
打印报表
"
;

this
.arvMain.Toolbar.Tools[
4
].ToolTip
=

"
拷贝
"
;

this
.arvMain.Toolbar.Tools[
6
].ToolTip
=

"
查找
"
;

this
.arvMain.Toolbar.Tools[
8
].ToolTip
=

"
单页显示
"
;

this
.arvMain.Toolbar.Tools[
9
].ToolTip
=

"
多页显示
"
;

this
.arvMain.Toolbar.Tools[
10
].ToolTip
=

"
连续滚动显示
"
;

this
.arvMain.Toolbar.Tools[
11
].ToolTip
=

"
缩放
"
;

this
.arvMain.Toolbar.Tools[
12
].ToolTip
=

"
缩小
"
;

this
.arvMain.Toolbar.Tools[
13
].ToolTip
=

"
放大
"
;

this
.arvMain.Toolbar.Tools[
14
].ToolTip
=

"
缩放
"
;

this
.arvMain.Toolbar.Tools[
16
].ToolTip
=

"
上一页
"
;

this
.arvMain.Toolbar.Tools[
17
].ToolTip
=

"
下一页
"
;

this
.arvMain.Toolbar.Tools[
18
].ToolTip
=

"
当前页码
"
;

this
.arvMain.Toolbar.Tools[
20
].ToolTip
=

"
后退
"
;

this
.arvMain.Toolbar.Tools[
20
].Caption
=

"
后退
"
;

this
.arvMain.Toolbar.Tools[
21
].ToolTip
=

"
前进
"
;

this
.arvMain.Toolbar.Tools[
21
].Caption
=

"
前进
"
;

this
.arvMain.Toolbar.Tools[
23
].Caption
=

"
注释
"
;

这种方法比较简洁,不过问题是不能汉化所有的按钮,另外一种方法是通过修改全球化文件的方式实现中文化,这是一种彻底、官方推荐的方法。

首先我们在安装目录上 X:/Program Files/Data Dynamics/ActiveReports for .NET 3.0/Localization/,拷贝这几个文件出来,

Viewer.zip、LocalizeViewer.bat、publickey.snk 把压缩包解压出来,修改里面的资源文件,用winres工具(.net内置的小工具),把节目的资源文件修改了,然后进行编译,得到一个程序集文件ActiveReports.Viewer3.resources.dll。把它放到不同语言的文件夹中就可以了,如中文文件夹是zh-CN(相对你的程序文件),程序运行后,就可以看到是中文的界面了。


附上一个我翻译好的资源文件和编译好的程序集文件,共享出来大家使用,希望对大家做报表的中文化有帮助(这可是我花了不少时间修改出来、编译好的文件,用的时候,记得饮水思源,顶下博客哈,呵呵),使用只需要把zh-CN文件夹原本拷贝到程序运行目录下,不用修改任何代码,就可以实现中文化了,实在太方便了!!

报表资源文件及编译好的程序集下载:
https://files.cnblogs.com/wuhuacong/ActiveReportCulture.rar

在上篇文章《
WinForm界面开发之布局控件"WeifenLuo.WinFormsUI.Docking"的使用
》,我介绍了如何在程序界面中使用WeifenLuo.WinFormsUI.Docking这个优秀的布局控件,这款软件目前我还没有找出比他更好的免费控件了,不知WeifenLuo其人如何,不过东西确实不错,赞一个。

在使用这个控件的时候,估计大家都会碰到 这样一个问题,就是当窗口是自动隐藏的时候,好像出来的大小一般比实际的大,感觉不太美观,有没有什么方法可以控制它的呢,答案是当然有了,其实实现起来也很简单。

首先我们来看看其内部机制是如何实现的,因为该控件有一些属性,专门用来控制窗口的比例的。我们在该控件的源码上看到DocingPanel类中有这么一个属性,是用来控制自动隐藏窗口的缩放比例的。

[LocalizedCategory(
"
Category_Docking
"
)]
[LocalizedDescription(

"
DockContent_AutoHidePortion_Description
"
)]
[DefaultValue(

0.25
)]

public

double
AutoHidePortion
{

get
{
return
DockHandler.AutoHidePortion;    }

set
{    DockHandler.AutoHidePortion
=
value;    }

}

默认的大小是0.25,这个参数是可以修改的。因为控件提供了一个保存布局状态的方法,它默认是没有保存的,如果需要记住调整的窗口大小(当然这是一种最好的方法),那么只需要加上几段代码即可。

首先我们看保存布局状态的代码。


private

void
MainForm_Closing(
object
sender, System.ComponentModel.CancelEventArgs e)
{

string
configFile
=
Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
"
DockPanel.config
"
);

if
(m_bSaveLayout)
dockPanel.SaveAsXml(configFile);

else

if
(File.Exists(configFile))
File.Delete(configFile);
}

这样的方法,因为是直接调用控件本身的保存,所以应该比较易懂。我们再看看程序启动的时候,加载还原原有布局信息的时候,是如何的。


private

void
MainForm_Load(
object
sender, EventArgs e)
{

//
加载布局


m_deserializeDockContent
=

new
DeserializeDockContent(GetContentFromPersistString);

string
configFile
=
Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
"
DockPanel.config
"
);

if
(File.Exists(configFile))
{
dockPanel.LoadFromXml(configFile, m_deserializeDockContent);
}
}


private
IDockContent GetContentFromPersistString(
string
persistString)
{

if
(persistString
==

typeof
(MainToolWindow).ToString())

return
mainToolWin;

else

if
(persistString
==

typeof
(FrmStatus).ToString())

return
mainStatus;

else

if
(persistString
==

typeof
(FrmRoomView).ToString())

return
frmRoomView;

else


return

null
;
}

这样,我们就可以实现布局由用户调整,而不需要怕每次都有那么一点大,不雅观了。

我们看程序的根目录下面生成了一个文件,叫做
DockPanel.config
, 我们看看就知道里面的布局状态参数了,其中的AutoHidePortion,我们通过自动调整界面,它也就会跟着变化的了,如下面的那个AutoHidePortion
=
"
0.179554494828958
"
就是我调整后的大小。


<
Contents Count
=
"
7
"
>


<
Content ID
=
"
0
"
PersistString
=
"
DockSample.DummyToolbox
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
True
"
IsFloat
=
"
True
"

/>


<
Content ID
=
"
1
"
PersistString
=
"
DockSample.DummySolutionExplorer
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
False
"
IsFloat
=
"
False
"

/>


<
Content ID
=
"
2
"
PersistString
=
"
DockSample.DummyPropertyWindow
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
False
"
IsFloat
=
"
False
"

/>


<
Content ID
=
"
3
"
PersistString
=
"
DockSample.DummyOutputWindow
"
AutoHidePortion
=
"
0.179554494828958
"
IsHidden
=
"
False
"
IsFloat
=
"
False
"

/>


<
Content ID
=
"
4
"
PersistString
=
"
DockSample.DummyTaskList
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
True
"
IsFloat
=
"
True
"

/>


<
Content ID
=
"
5
"
PersistString
=
"
DockSample.DummyDoc,,Document1
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
False
"
IsFloat
=
"
False
"

/>


<
Content ID
=
"
6
"
PersistString
=
"
DockSample.DummyDoc,,Document2
"
AutoHidePortion
=
"
0.25
"
IsHidden
=
"
False
"
IsFloat
=
"
False
"

/>


</
Contents
>

当然如果我们需要 完美的布局,只需要在发布前,调整好这些参数给用户就可以了,是不是很方便呢。

在我上篇文章《
利用Database2Sharp生成的EnterpriseLibrary架构的特点
》中,主要介绍了利用该框架如何组建大型的企业应用管理系统,在其中描述了管理系统的各方面,包括:框架的总体设计、权限管理、业务模块管理、菜单管理、工作流管理、通用数据字典管理等各方面,该文章主要是从一个系统框架的宏观方面进行描述,其中并未涉及太多的代码细节。其实自该模版框架诞生以来,本人所有的程序(包括Web和Winform程序),都统一采用Database2Sharp自动生成该框架代码,也包括各种数据库方面的应用(SqlServer、Access、Oracle),都是统一接口,统一开发模型。

(Database2Sharp下载地址:
http://www.iqidi.com/database2sharp.htm

本文主要从该框架的细节方面向大家展现框架的各层内容以及封装原理,透析框架代码的精妙之处,方便所在。首先我们回顾下该框架的分层架构图。

EnterpriseLib.jpg

代码架构类似Petshop的架构,不过由于基类采用了泛型的封装,在构建对象的时候,属于强类型的对象,智能提示也比较好。数据访问基类的代码如下所示。


///

<summary>


///
数据访问层的基类

///

</summary>



public

abstract

class
BaseDAL
<
T
>
: IBaseDAL
<
T
>

where
T : BaseEntity,
new
()
{




}

我通过在基类封装了各种数据库操作方法(几乎能满足各种要求的方法集合),因此具体的数据库访问对象,基本上不需要做数据访问的代码编写了。我们再来看看具体的数据访问对象(对应具体表的对象)代码是如何的。


///

<summary>


///
具体表的数据访问对象

///

</summary>



public

class
Customer : BaseDAL
<
CustomerInfo
>
, ICustomer
{

//...................

}

基本上,如果我们需要特殊的函数,我们只需要在ICustomer接口中定义,并在这个类中实现这个接口就可以了。虽然定义接口又实现,会感觉比较麻烦,但是你这样做,很快可以感觉到面向接口的优点了。

其中的接口定义是这样的,代码如下。


///

<summary>


///
ICustomer 的摘要说明。

///

</summary>



public

interface
ICustomer : IBaseDAL
<
CustomerInfo
>

{
}

另外我们再看看业务规则基类,它也是采用了泛型和和反射的方式来实现。


public

class
BaseBLL
<
T
>

where
T : BaseEntity,
new
()
{

private

string
dalName
=

""
;

protected
IBaseDAL
<
T
>
baseDal
=

null
;

public
BaseBLL() :
this
(
""
)
{
}

public
BaseBLL(
string
dalName)
{

this
.dalName
=
dalName;

if
(
string
.IsNullOrEmpty(dalName))
{

this
.dalName
=
GetType().Name;
}

baseDal

=
Reflect
<
IBaseDAL
<
T
>>
.Create(
this
.dalName,
"
WHC.OrderWater.DAL
"
);
}



}

继承基类的业务类代码如下所示。


public

class
Customer : BaseBLL
<
CustomerInfo
>

{

public
Customer() :
base
()
{
}


///

<summary>


///
获取所有的客户编号

///

</summary>


///

<returns></returns>



public
List
<
string
>
GetAllCustomerNumber()
{
ICustomer customerDAL

=
baseDal
as
ICustomer;

return
customerDAL.GetAllCustomerNumber();
}


///

<summary>


///
根据客户编号获取客户信息

///

</summary>


///

<param name="number"></param>


///

<returns></returns>



public
CustomerInfo GetByCustomerNumber(
string
number)
{
ICustomer customerDAL

=
baseDal
as
ICustomer;

return
customerDAL.GetByCustomerNumber(number);
}
}

public

class
Customer : BaseBLL
<
CustomerInfo
>

{

public
Customer() :
base
()
{
}


///

<summary>


///
获取所有的客户编号

///

</summary>


///

<returns></returns>



public
List
<
string
>
GetAllCustomerNumber()
{
ICustomer customerDAL

=
baseDal
as
ICustomer;

return
customerDAL.GetAllCustomerNumber();
}


///

<summary>


///
根据客户编号获取客户信息

///

</summary>


///

<param name="number"></param>


///

<returns></returns>



public
CustomerInfo GetByCustomerNumber(
string
number)
{
ICustomer customerDAL

=
baseDal
as
ICustomer;

return
customerDAL.GetByCustomerNumber(number);
}
}

这样的代码虽然看起来比较复杂,又有继承又有泛型的,但是这些都不需要你的操心,你设计好数据库后,采用Database2Sharp代码生成工具(
http://www.iqidi.com/Database2Sharp.htm
)生成代码,所有这些都会有的,包括各种包含丰富API的基类和对象的继承关系,实体类、以及所需的辅助类等框架代码都一应俱全。不需要额外的操心,这些都是生成后马上可以运行,而且代码也是支持SqlServer、Access、Oracle几种数据库。

生成的框架代码支持Web和Winform方式的数据访问(默认Web界面也同时生成了,Winform的目前没有,需要自己弄界面),业务层和界面是独立的。

如果没有需要特别的处理,那么你的程序获取数据,只需要通过这样的方式就可以实现操作数据库了(下面是Winform的例子)。



if
(
!
string
.IsNullOrEmpty(ID))



{

CustomerInfo info

=
BLLFactory
<
Customer
>
.Instance.FindByID(ID);

if
(info
!=

null
)



{

SetInfo(info);


try




{

bool
succeed
=
BLLFactory
<
Customer
>
.Instance.Update(info, info.ID);

MessageUtil.ShowTips(

"
保存成功
"
);

this
.DialogResult
=
DialogResult.OK;

}



catch
(Exception ex)



{

LogHelper.Error(ex);

MessageUtil.ShowError(ex.Message);

}



}



}



else




{

CustomerInfo info

=

new
CustomerInfo();

SetInfo(info);

info.ID

=
Guid.NewGuid().ToString();


try




{

bool
succeed
=
BLLFactory
<
Customer
>
.Instance.Insert(info);

MessageUtil.ShowTips(

"
保存成功
"
);

this
.DialogResult
=
DialogResult.OK;


}



catch
(Exception ex)



{

LogHelper.Error(ex);

MessageUtil.ShowError(ex.Message);

}



}

整个框架是面向对象的数据处理方式,所有的业务类通过BLLFactory<Customer>.Instance出来的对象都是强类型的,具有所有Customer业务类的一切智能提示,非常方便操作,而不是一个通用的数据库操作类。

在本文的介绍中,所有的接口开发模型都是各种数据库通用的,不同的数据库中,只需要更换BaseDAL这个基类实现就可以了,其他的完全不用动,因此切换各种数据库是非常方便的(虽然切换数据库这种情况不多,但是由于一些需要,从SqlServer切换到Access还是经常有的)。

在开发的世界里,效率是金钱,代码就是一切,本文主要介绍了Database2Sharp中Enterprise Library架构中的一些底层封装思路,帮助各位能够快速理解它的精妙,加入到利用Database2Sharp开发的阵营中来,当然也希望更多的支持这款软件的发展。

为了更直接的了解各种数据库开发的模型,本文附带了三种不同的数据库例子,包括SqlServer、Access、Oracle,这三种是最常用的了,本文代码测试可以正常运行,附带有所需的数据库或者脚本。本例子是基于我的送水管理系统的客户管理界面的一部分,抽取出来左右学习交流使用,其中用到了Winform的分页控件(
WinForm界面开发之“分页控件”
),如果有不明白的地方,可以在博客上讨论学习下。

为了感官认识,先贴一个Oracle例子的界面出来,其他的界面雷同。

下面是几个不同数据库的测试例子(变化的只是BaseDAL部分)

https://files.cnblogs.com/wuhuacong/TestWinFormSqlserver.rar

https://files.cnblogs.com/wuhuacong/TestWinFormOracle.rar

https://files.cnblogs.com/wuhuacong/TestWinFormAccess.rar

Database2Sharp生成的Enterprise架构相关文章列表:

一个分层架构设计的例子(1)

一个分层架构设计的例子(2)

利用Database2Sharp生成的EnterpriseLibrary架构的特点

Database2Sharp重要更新之完善EnterpriseLibrary架构代码

自动增长的主键字段是个好东西,提供了一个比较有意义和可阅读的字段内容(相对GUID来说),插入的时候,不用管它的值,数据库自动追加;但它也是一个不好的东西,如果管理不好,可能会造成冲突。本文暂且不讨论其优劣,因为存在就是硬道理,很多时候,我们都是采用自增长字段的,特别是对于SqlServer数据开发来说。

本文阐述一下在
Database2Sharp(软件下载地址:
http://www.iqidi.com/database2sharp.htm

生成的Enterprise Library架构如何实现Oracle的自增长的支持。同时也会顺带说说对SqlServer、Access的实现。

Database2Sharp生成的Enterprise Library架构其实对Oracle内置了对自增长序列的支持,在数据库访问层的基类BaseDAL中,我们看到下面的代码。


///

<summary>


///
数据访问层的基类

///

</summary>



public

abstract

class
BaseDAL
<
T
>
: IBaseDAL
<
T
>

where
T : BaseEntity,
new
()
{

#region
构造函数



protected

string
tableName;
//
需要初始化的对象表名



protected

string
primaryKey;
//
数据库的主键字段名



protected

string
sortField
=

"
ID
"
;
//
排序字段



private

bool
isDescending
=

false
;
//



protected

string
selectedFields
=

"
*
"
;
//
选择的字段,默认为所有(*)



private

string
seqField
=

""
;
//
指定那个字段是用序列来控制它的值的,一般为主键



private

string
seqName
=

""
;
//
指定的序列名称,建议规则为:SEQ_表名称




///

<summary>


///
指定那个字段是用序列来控制它的值的,一般为主键

///

</summary>



public

string
SeqField
{

get
{
return
seqField; }

set
{ seqField
=
value; }
}


///

<summary>


///
指定的序列名称,建议规则为:SEQ_表名称

///

</summary>



public

string
SeqName
{

get
{
return
seqName; }

set
{ seqName
=
value; }
}


这段代码定义了两个属性,一个是序列字段名称(一般是主键,如ID),一个是我们为该字段指定的序列对象名称,我们这里建议的名称是"SEQ_表名称",当然也可以使用任意的名称,合理统一就可以了。这两个属性在基类不需要修改,只需要在具体的数据访问对象(如数据访问层中的Customer类)构造函数中,指定序列字段和序列对象即可。

下面我们看看表盒序列的脚本代码,例如我创建一个客户表,其字段ID为自增序列,我的创建脚本是。

create

table
ALL_CUSTOMER

(

ID
NUMBER

not

null
,

USERNUMBER
VARCHAR2
(
50
),

NAME
VARCHAR2
(
50
),

TYPE
VARCHAR2
(
50
),

AREA
VARCHAR2
(
50
),

COMPANY
VARCHAR2
(
50
),

ADDRESS
VARCHAR2
(
50
),

TELEPHONE1
VARCHAR2
(
50
),

TELEPHONE2
VARCHAR2
(
50
),

TELEPHONE3
VARCHAR2
(
50
),

TELEPHONE4
VARCHAR2
(
50
),

TELEPHONE5
VARCHAR2
(
50
),

CREATEDATE  DATE,

SHOP_ID
VARCHAR2
(
50
),

NOTE
VARCHAR2
(
255
),

LASTUPDATED DATE,

constraint
PK_ALL_CUSTOMER
primary

key
(ID)

);


create
sequence SEQ_ALL_CUSTOMER

minvalue
1


maxvalue
999999999999999999999999999


start
with

1220


increment
by

1


cache
20
;


commit
;

注意
SEQ_ALL_CUSTOMER就是序列对象名称,那么我们再插入的时候,应该如何写入序列字段的值,并且获得新的值作为返回值的呢?

在BaseDAL中,有一个Insert2的方法,是专门处理 自增序列函数,并且返回创建记录的自增字段的值的,我们来看看其源码。


///

<summary>


///
添加记录

///

</summary>


///

<param name="recordField">
Hashtable:键[key]为字段名;值[value]为字段对应的值
</param>


///

<param name="targetTable">
需要操作的目标表名称
</param>


///

<param name="trans">
事务对象,如果使用事务,传入事务对象,否则为Null不使用事务
</param>



public

int
Insert2(Hashtable recordField,
string
targetTable, DbTransaction trans)

{

int
result
=

-
1
;

string
fields
=

""
;
//
字段名



string
vals
=

""
;
//
字段值



if
(recordField
==

null

||
recordField.Count
<

1
)

{

return
result;

}


List
<
OracleParameter
>
paramList
=

new
List
<
OracleParameter
>
();

IEnumerator eKeys
=
recordField.Keys.GetEnumerator();


while
(eKeys.MoveNext())

{

string
field
=
eKeys.Current.ToString();

fields
+=
field
+

"
,
"
;

if
(
!
string
.IsNullOrEmpty(seqField)
&&

!
string
.IsNullOrEmpty(seqName)

&&
(field
==
seqField))

{

vals
+=

string
.Format(
"
{0}.NextVal,
"
, seqName);

}

else


{

vals
+=

string
.Format(
"
:{0},
"
, field);

object
val
=
recordField[eKeys.Current.ToString()];

paramList.Add(
new
OracleParameter(
"
:
"

+
field, val));

}

}


fields
=
fields.Trim(
'
,
'
);
//
除去前后的逗号


vals
=
vals.Trim(
'
,
'
);
//
除去前后的逗号



string
sql
=

string
.Format(
"
INSERT INTO {0} ({1}) VALUES ({2})
"
, targetTable, fields, vals);


Database db
=
DatabaseFactory.CreateDatabase();

DbCommand command
=
db.GetSqlStringCommand(sql);

command.Parameters.AddRange(paramList.ToArray());


if
(trans
!=

null
)

{

db.ExecuteNonQuery(command, trans);


sql
=

string
.Format(
"
SELECT {0}.Currval ID From Dual
"
, seqName);

command
=
db.GetSqlStringCommand(sql);

result
=
Convert.ToInt32(db.ExecuteScalar(command, trans).ToString());

}

else


{

db.ExecuteNonQuery(command);


sql
=

string
.Format(
"
SELECT {0}.Currval ID From Dual
"
, seqName);

command
=
db.GetSqlStringCommand(sql);

result
=
Convert.ToInt32(db.ExecuteScalar(command).ToString());

}


return
result;

}

其中我们判断是否有自增序列ID和其名称(非空字符),如果有则使用这段代码,来写入自增序列的下一个值
NextVal
(新增值),作为这个字段的值。

vals
+=

string
.Format(
"
{0}.NextVal,
"
, seqName);

如果要返回插入的自增序列值,那么我们使用序列对象的
Currval
就可以了。下面是返回插入的字段内容。

sql
=

string
.Format(
"
SELECT {0}.Currval ID From Dual
"
, seqName);

这样对于写入新的自增长值并返回就实现了。


对SqlServer和Access自增长字段的支持

对于SqlServer,实现自增长字段就更加方便了,由于没有Oracle序列对象那么麻烦,所以只需要在具体的数据库访问对象中,构建写入字段的Hash表中,忽略该字段就可以了(代码已经自动生成,不用管理的)。其返回刚刚插入的自增内容,则在插入的语句后面增加一条语句就可以了,语句如下。

SELECT

SCOPE_IDENTITY
()

对于Access的数据库,原理和SqlServer一样,不过需要返回刚刚插入的自增长值的时候,使用这段语句就可以了。

SELECT

@@IDENTITY

对于SqlServer和Access,只要设计好数据库的自增字段,自动生成的代码中,数据访问类是不用修改任何信息,就可以完美支持自增序列。