近日拜读了孙兄(http://sunnyym.cnblogs.com/)的大作websharp,感受了此ORM框架设计思想,但同时也发现一些小问题,顺便提出来,供大家交流之用,若有理解偏差或理解错误之处,还望海涵^-^。
接触此框架有一段时间了,一直以来都没时间细读,近来有机会细读一下,收获颇丰,但同时也发现里面的一些小问题,也许是由于我测试的数据库是用的oracle,于是便记录下来供大家讨论参考,错误之处,还请批评指正,再者就是希望此框架能够不断进步,茁壮成长,我认为只由不断有发现问题,分析问题,解决问题,才能集思广益,不断发展。
1.先说一处失误,在Websharp.Data项目中OracleDataAccess.cs文件,属性DatabaseType应为Oracle,可能作者直接从MSSQLServer复制过来,没时间去理会这此东东^-^.
2.由于不同数据库数据访问时有一定的差异,所以对应的查询参数应该按不同数据库类型有所区分,比如:Oracle数据库在对字符串空值的处理方面就与SqlServer不同,Oracle中是用null来对String的空值存储的,若有下面的例子:
1
T1 t1
=
EntityManager.CreateObject(
typeof
(T1))
as
T1;
2
t1.A
=
"
3333
"
;
3
t1.B
=
null
;
4
t1.C
=
""
;
如果对上面的实体进行执行,就会出现错误,因为Oracle不能直接对像t1.C这样的空值进行处理,如果改为t1.C = null则不会出现错误,而SQLServer中则直接可以,所以在参数查询时需要对Oracle进行转换,下面就是一种较简单的一种处理方式,在Websharp.Data项目的QueryParameter.cs文件中加入一个简单处理函数及一些处理代码
1
2
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/// <summary>
3
/// 方法名称: ConvertOracle
4
/// 内容描述: 完成当前参数的Oracle转换
5
/// 实现流程:
6
/// 作 者: XXX
7
/// 日 期: 2006-2-22 11:24:16
8
/// </summary>
9
/// <param name="obj">需要转换的对象</param>
10
/// <param name="type">当前对象类型</param>
11
internal
object
ConvertOracle(
object
obj,System.Type type)
12
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
13
object strReturn = obj;
14![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
15
if ((type == typeof(System.String)) && (obj.ToString() == ""))
16![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
17
strReturn = System.DBNull.Value ;
18
}
19
else if (type == typeof( System.DateTime ))
20![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
21
System.DateTime time = Convert.ToDateTime( obj );
22
strReturn = time.ToString("yyyy-MM-dd HH:mm:ss");
23
}
24
25
return strReturn;
26
}
27
![None.gif](/Images/OutliningIndicators/None.gif)
28
在方法InitRealParameter中Oracle的处理项下加入下面代码:
1
//
XXX 2006-2-22 11:35:32 完成Oracle数据转换
2
object
objvalue;
3
objvalue
=
Value ;
4
objvalue
=
this
.ConvertOracle(objvalue,objvalue.GetType());
5
Value
=
objvalue;
上面的方法只能完成一些简单差异转换,其它一些差异可以参考一些其它开源的ORM框架。
3,在Oracle中自增量的ID是通过Sequence实现的,所以也需要对此进行特殊处理,其实也就是执行一个SQL语句获取就OK
既然是执行SQL语句,我们当然可以直接定义DataAccess访问对象,但出于对框架的整体性与可维护性考虑,最好不这样做,
因为有PersistenceManager接口,应当用此接口进行数据持久化操作。
在PersistenceManager接口中,已经有一个DataAccess NewDataAccess(),此项为新建一个访问对象,其实此接口在构造函数中
已经实例化过一个DataAccess,应该不用再创建新的访问对象了,直接获取当前持久层管理对象PersistenceManager内部的访问
对象岂不更好。于是应该在PersistenceManager接口中增加一个访问接口GetDataAccess(),当然对象的实现SingleTablePM.cs文件
也要实现返回当前的数据访问对象。
处理方式为:在Websharp.ORM.Base项目的PersistanceManager.cs文件及SingleTablePM.cs文件中增加如下代码:
1
/**/
/// XXX 2006-2-22 15:24:53 修改加入直接访问DataAccess层的接口
2
DataAccess GetDataAccess();
3
1
2
public
DataAccess GetDataAccess()
3
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
4
return this.dao;
5
}
获取Sequence的方法(直接执行SQL语句)如下:
1
2
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/// <summary>
3
/// 获取数据库连接属性
4
/// </summary>
5
/// <param name="ci"></param>
6
/// <returns></returns>
7
public
static
DatabaseProperty GetDatabaseProperty(CultureInfo ci)
8
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
9
string ciPostfix = null;
10
if (ci != null)
11
ciPostfix = "." + ci.Name;
12
DatabaseProperty dp = new DatabaseProperty();
13
string databaseType = ConfigurationSettings.AppSettings["AppDB.DatabaseType" + ciPostfix];
14
dp.DatabaseType = (DatabaseType) Enum.Parse(typeof(DatabaseType),
15
(databaseType == null ? "Oracle" : databaseType), true);
16
dp.ConnectionString = ConfigurationSettings.AppSettings["AppDB.ConnectionString" + ciPostfix];
17
return dp;
18
}
19
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**/
/// <summary>
20
/// 使用数据库定义的序列对象为实体生成新的Id值。访问数据库中所有实体表对应的序列对象。
21
/// </summary>
22
/// <param name="entityType">实体类型。</param>
23
/// <param name="CultureInfo">多语言参数,System.Threading.Thread.CurrentThread.CurrentCulture</param>
24
/// <returns>返回生成的唯一Id。</returns>
25
/// <remarks>
26
/// 实现流程:
27
/// 1.使用反射机制获取实体类型绑定的TableMap属性,获取实体类型对应的表和关键字。
28
/// 2.使用PersistenceManager直接执行查询调用表对应的序列对象生成Id值。
29
/// 注:默认数据库设计时已经为每个实体表定义了序列对象,并且序列对象命名
30
/// 满足以下格式:
31
/// S_[表名]
32
/// </remarks>
33
public
static
long
GenerateIdentity(Type entityType,CultureInfo ci)
34
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
35
object[] attributes = entityType.GetCustomAttributes(typeof(TableMapAttribute), true);
36
if (attributes != null && attributes.Length > 0)
37![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
TableMapAttribute tableMap = (TableMapAttribute) attributes[0];
39
string sql = string.Format("SELECT S_{0}.nextval FROM DUAL", tableMap.TableName);
40![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
41
PersistenceManager pm =
42
PersistenceManagerFactory.Instance().CreatePersistenceManager(GetDatabaseProperty(ci));
43![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
44
DataAccess da = pm.GetDataAccess();
45![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
46
Transaction currentTrans ;
47
currentTrans = pm.CurrentTransaction;
48![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
49
currentTrans.Begin();
50![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
51
try
52![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
53
long logidentity;
54![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
55
logidentity = Convert.ToInt64(da.ExecuteScalar(sql));
56![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
57
currentTrans.Commit();
58![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
59
return logidentity;
60
}
61
catch
62![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
63
currentTrans.Rollback();
64
throw;
65
}
66
}
67
else
68![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
69
throw new Exception("指定类型不是一个实体类。");
70
}
71
}
72
![None.gif](/Images/OutliningIndicators/None.gif)
73