自动增长的主键字段是个好东西,提供了一个比较有意义和可阅读的字段内容(相对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,只要设计好数据库的自增字段,自动生成的代码中,数据访问类是不用修改任何信息,就可以完美支持自增序列。