当我们去操作数据库的时候都必须构建一个组件的环境对象,似乎这种传统的操作模式这样做是必须的也没有什么问题(就如同你在传统ADO.NET方式下操作数据打开连接一下).但细想一下会发现一个问题,很多时候的应用只是针对一个数据库;既然很多时候只针对一个数据库为什么组件在设计时不提供一个缺省的操作模式呢?让数据操作上节省了构造组件访问对象这一步(当然也应该提供,因为总要面对同时操作多个数据库的时候).
其实设计这种访问模式并不难,只需要在设计的时候提供一些缺省参数方法即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public IList<T> List<T>(Region region, params string [] orderby) where T : Mappings.DataObject, new () { ObjectMapper om = ObjectMapper.GetOM( typeof (T)); using (IConnectinContext cc = om.Connection.GetContext()) { return List<T>(cc, region, orderby); } } public IList<T> List<T>(IConnectinContext cc, Region region, params string [] orderby) where T : Mappings.DataObject, new () { ObjectMapper om = ObjectMapper.GetOM( typeof (T)); string strob = null ; if (orderby != null && orderby.Length > 0) strob= string .Join( "," , orderby); return EntityBase.ExOnList<T>(cc, om.GetSelect(), this , region, strob, om.GroupBy); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public int Delete<T>() { ObjectMapper om = ObjectMapper.GetOM( typeof (T)); using (IConnectinContext cc = om.Connection.GetContext()) { return Delete<T>(cc); } } public int Delete<T>(IConnectinContext cc) { ObjectMapper om = ObjectMapper.GetOM( typeof (T)); return EntityBase.ExOnDelete(cc, om.Table, this ); } |
当组件提供缺省方法后,那数据操作的时候自然就可以省下了Context的创建
1
2
3
4
5
|
exp = Employee.employeeID == 6; var employees = exp.List<Employee>(); var orders = exp.List<Order>(); exp.Delete<Employee>(); exp.Delete<Order>(); |
这样用起来似乎很省事,但仔细一想就发现一个比较严重的问题.对于以上代码那两个Delete方法要在一个事务环境怎办?因为有相关的Context参数方法可以修改一下,把参数带进去就完事了.但既然提供默认环境Context,那组件就应该提供在不更改此方法调用的情况能把这两个方法整合到事务中.
为了达到上面所说的要求,那同一数据库Context的设计中必须在线程中保持唯一的.要做到这一点那在Context构造的时候必须下点功夫.
1
2
3
4
5
6
7
8
9
10
|
public static IConnectinContext GetConnection(ConnectionType connection) { if (connection.GetHashCode() > Config.Connections.Count) throw new SmarkDataException( string .Format(DataMsg.DATABASE_SETTING_NOTFOUND, connection)); ConnectionElement ce = Config.Connections[connection.GetHashCode()]; IDriver driver = ce.Driver; if (driver == null ) throw new SmarkDataException( string .Format(DataMsg.DATABASE_SETTING_NOTFOUND, ce.Name)); return new ConnectionContext(ce.ConnectionString, driver, connection); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class ConnectionContext : IConnectinContext { public ConnectionContext( string db, IDriver driver, ConnectionType type) { mDB = db; mHandler=DBContext.CurrentHandler(db); if (mHandler== null ) { mHandler=DBContext.AddConnectionHandler(mDB, driver); mActiveConnection = true ; } Type = type; } |
从以上代码可以看到,在构造一个Context的时候先从当前线程中检过存不存在Context, 存在就获取设置;如果不存就构建一个新的Context,并标记为当前激活.为什么要标记激活呢,因为只是激活标记的的对象才能释放Context.这样就能解决在嵌套的时候,内部的Context释放了导致外层的不能工作出现异常.
除了在Context中构造需要这样处理外,还有在Context的事务处理也要按以上方法实现,要不然就存在内嵌Context事务提交或释放后导致外层Context错误.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public void BeginTransaction() { if (mHandler.Transaction == null ) { mHandler.BeginTransaction(); mActiveTransaction = true ; } } public void Commit() { if (mActiveTransaction) { mHandler.Commit(); } } public void Rollback() { if (mActiveTransaction) { mHandler.Rollback(); }; } |
这种实现模式不紧紧能节少数据访问的时的代码,还能达到一个Context跨方法的作用,从而非常方便就能把不同方法的处理整合到一个事务中而不需要修改方法参数.