为了规避IBatisNet的空值问题,AppFramework不使用C#基本类型来构造实体类。AppFramework对C#基本类型作了简单封装,增加了一个是否有值的属性来标志字段值是否非空。
每一种基本的C#类型都有对应的DBValue对其进行封装。
C#类型
|
DBValue类型
|
数据库类型
|
byte
|
ByteValue
|
数字类型
|
short
|
ShortValue
|
数字类型
|
int
|
IntValue
|
数字类型
|
long
|
LongValue
|
数字类型
|
sbyte
|
SByteValue
|
数字类型
|
ushort
|
UShortValue
|
数字类型
|
ulong
|
ULongValue
|
数字类型
|
uint
|
UIntValue
|
数字类型
|
DateTime
|
DateTimeValue
|
日期时间
|
string
|
StringValue
|
Varchar/NVarchar 或
Text/CLOB类型
|
float
|
FloatValue
|
数字类型
|
double
|
DoubleValue
|
数字类型
|
decimal
|
DecimalValue
|
数字类型、金额
|
byte[]
|
BLOBValue
|
BLOB类型
|
1.1.2 DBValue的属性方法
在AppFramework
里, DBValue
主要用于构造数据库的表实体类。代码生成器为每个数据表生成一个实体类,为每个表字段生成一个子类化的DBValue
属性,并自动实现实体类的构造、赋值。测试数据表明,虽然DBValue
构造的实体类比用C#
基本类型构造的实体类要“重”一些,但其构造对象的性能比IBatis
用反射的方式构造对象的性能还是高很多。
下表简单列举了DBValue
的基本属性和方法:
属性/
方法
|
类型
|
说明
|
HasValue
|
Bool
|
标志字段是否有值,构造时初始化为false
|
Object
|
Object
|
获取或设置字段内部封装的值,如果 HasValue
为 false,
获取时得到 null
|
DBObject
|
Object
|
获取或设置字段内部封装的值,如果 HasValue
为 false,
获取时得到 DBNull.Value;
如果设置 DBNull
,则 HasValue
改变为 false;
|
Value
|
封装的C#
类型
|
获取字段值,HasValue
为 false
时获取 Value
值将获得所封装类型的默认值
|
ToString()
|
String
|
显示为文本,如果HasValue
为false
,则返回string.Empty
|
Clear()
|
Void
|
把HasValue
设置为false
,但清除Value
值
|
例如,IntValue
封装了 int
类型的数据库字段,IntValue.HasValue
表示是否有值,如果没有值访问IntValue.Value
属性会得到int
的默认值。对无值的IntValue
调用ToString()
会得到空字符串。
正确的用法应该是先通过HasValue
判断是否有值,然后在访问Value
获取值。
public BasUser GetUser(string fields, int id)
{
//
获得
dao
IBasUserDAO dao = DAOManager.Default.GetDAO<IBasUserDAO>();
//
获得数据库会话
using (IDBSession session = DBSessionManager.Default.GetSession())
{
return dao.Get(session, fields, id);//
返回得到的实体,如果未找到记录,返回
null
}
}
public void ShowUser(int userID)
{
BasUser user = GetUser(userID);
if (user != null)
{
txtName.Text = user.Name.ToString();
txtAge.Text = user.Age.ToString();
}
}
}
DBField封装的基本目的是表达C#原始类型的所不能表达的“空值”、“默认值”、“表达式”等信息,其结构为“字段名—操作符—表达式”,在AppFramework中主要用于插入和更新数据库记录时为数据库字段赋值或表达式。经过扩展,也适用于各一些表达 “字段名—操作符—表达式”结构的SQL语句片段,例如“字段名 in (select … from)”这样的子查询。
DBField封装了各种通用的数据库字段类型,如下表:
C#类型
|
DBField类型
|
数据库类型
|
Object
|
DBField
|
通用类型
|
Byte
|
ByteField
|
数字类型
|
Short
|
ShortField
|
数字类型
|
Int
|
IntField
|
数字类型
|
Long
|
LongField
|
数字类型
|
Sbyte
|
SByteField
|
数字类型
|
Ushort
|
UShortField
|
数字类型
|
Ulong
|
ULongField
|
数字类型
|
uint
|
UIntField
|
数字类型
|
DateTime
|
DateTimeField
|
日期时间
|
string
|
StringField
|
Varchar/NVarchar
|
string
|
TextField
|
Text/CLOB类型
|
float
|
FloatField
|
数字类型
|
double
|
DoubleField
|
数字类型
|
decimal
|
DecimalField
|
数字类型、金额
|
byte[]
|
BLOBField
|
BLOB类型
|
注意:DBField比DBValue多了对两种基础类型的封装,一个是DBField对object的封装,另一个是TextField对CLOB/TEXT大文本字段的封装。
1.1.4 DBField的属性方法
下表简单列举了DBField的基本用法:
属性/方法
|
类型
|
说明
|
FieldName
|
string
|
获取或设置字段名
|
Operator
|
DBOperator
|
获取或设置字段操作符,例如大于、小于、等于、in、like……等常用操作符,默认为 Equal
|
Value
|
封装的C#类型
|
获取字段值,HasValue 为 false 时获取 Value 值将获得所封装类型的默认值
|
Expression
|
string
|
获取或设置字段表达式
|
Flag
|
DBFieldFlag
|
获取字段值状态标志,当标志值为NotSet时表示未设置值,标志值为Value 表示此对象的Value属性有效; Expression表示此对象的Expression有效。默认为 NotSet。
|
DataType
|
DataType
|
获取或设置字段值类型
|
AsObject
|
object
|
以 object 方式获取或设置字段值,如果 Flag为 NotSet, 获取时得到 null
|
SelectStatement
|
SelectStatement
|
获取或设置字段的子查询表达式
|
SetDefault()
|
void
|
设置字段为其默认值
|
SetNull()
|
void
|
设置字段为空值
|
Clear()
|
void
|
清除字段值或表达式,把Flag设置为NotSet
|
ToString()
|
string
|
已重载。若Flag为NotSet,返回string.Empty。若Flag为Value,则返回Value.ToString()。若Flag为Expression,则返回Expression。
|
为了方便使用,提供了几个静态方法快速创建各种DBField:
方法
|
返回值
|
说明
|
CreateExpression
|
DBField
|
创建一个表达式,有多个重载,可以对各个属性进行设置。
string fieldName:字段名
DataType t:字段类型
DBOperator op:表达式的操作符
string expression:表达式
|
CreateDefault
|
DBField
|
创建一个默认值字段
|
CreateNull
|
DBField
|
创建一个空值字段
|
Create
|
DBField
|
虚方法,子类将重载,创建一个子类DBField
|
通过IDBSession和DBFieldk可以轻松实现insert和update:
//
插入记录
insert
using (IDBSession session = DBSessionManager.Default.GetSession())
{
//
插入记录
session.Insert(
“BAS_USER”,
new DBField(“Name”, “
王二
”),
new DBFieldI(“En_Name”, “Wanger”)
……
new DBFieldI(“Age”, 26)
);
}
//
更新记录
update
using (IDBSession session = DBSessionManager.Default.GetSession())
{
string updateCondition = “id = 100”;
//
更新记录
session.Update(
“BAS_USER”,
updateCondition,
new DBField(“Name”, “
王二
”),
new DBFieldI(“En_Name”, “Wanger”)
……
new DBFieldI(“Age”, 26)
);
}
用IDBSession实现insert和update是一种高效的数据插入和更新方式,测试数据表明其性能超过iBatis的插入更新性能的60~100%。
为了进一步简化代码,AppFramework采用生成DAO和参数实体类(由DBField组成的实体类)实现插入和更新。下列代码中BasUserParam是一个参数实体类,其属性均为子类化的DBField,对其属性赋值后传给DAO的Insert或Update方法实现插入或更新:
//
构造用户信息参数类
IBasUserParam user = new BasUserParam();
user.Name.Value = "MyBasName";
user.EnName.Value = "EnMyBasName" ;
user.CreatorID.Value = 0;
user.DeptID.Value = 100;
user.Email.Value = "Email";
user.EmployeeNo.Value = "EmployeeNO" ;
user.OrgID.Value = 0;
user.Password.Value = "Password";
user.State.Value = 0;
user.UpdatedBy.Value = 0;
user.Age.Value = 25;
user.LastUpdatedTime.SetDefault();
//
获得
dao
IBasUserDAO dao = DAOManager.Default.GetDAO<IBasUserDAO>();
//
获得数据库会话
using (IDBSession session = DBSessionManager.Default.GetSession())
{
dao.Insert(session, user); //
插入记录
return user.ID.Value;//
返回新用户的
ID
}