功能与接口定义
数据访问层的设计我研究了很长时间,关于接口的定义,好几次都推翻重来。
园子看到过很多easyui+MVC+EF的文章,在早期,我的设计也类似。
但是后来为了增强它,想加点功能通用的功能进去,就耗费了非常多的时间。
这是一个怎么样的DAL?
也许你已经见过许多实用EF的架构了,它是一套基于领域模型架构中的DAL。
大致结构如图中,DAL就是最下面的那一层。
它的主要功能也体现在图中了:增删改服务、查询、事务管理、并发,另外事务中包括工作单元,查询中包括延迟加载。
我们希望底层的数据库操作对其他层来说是透明的。
例如BLL将感受不到ORM工具的存在,他也不需要知道我们操作的数据库是Oracle,还是MSSQLServer。
所以需要给DAL抽象出一个统一的接口,供其他层来操作,而底层我们可以分别使用各种ORM工具,或者原生SQL去实现。
看到图中,会发现设计好DAL统一的上下文是重点,因为它将会提供给其他层统一的接口,接口的定义是一个难点。
一个比较好的设计是底层实现依赖与高层抽象,而DAL不能去依赖EFDAL/NHDAL,这里使用IOC工具就能轻松实现。
关于上下文的类图:
IDataContext就是DAL的上下文,而它需要被EF的上下文(context)/NH的上下文(session)分别实现,而原生的SQL只能通过实现它的接口来构成所谓的上下文。
其中BaseDataContext就是实现了一些通用的功能,比如事务管理、工作单元、唯一标识。
你会发现许多人都在BLL直接使用ORM的上下文,那是因为DAL并没有提供统一的上下文接口,只是提供了一个统一的仓储接口(IRepository,比如IUserRepository)。
所以BLL只能使用仓储接口,而不能使用上下文中事务管理和工作单元,为了的条件查询要么让仓储提供更多的查询方法,DAL中ORM特定的上下文贯穿所有层。
在上一篇BLL调用DAL的演示中,主要为了说明业务层事务控制方法,这次贴一个更加具体的例子。
[Test] public void QueryTest() { IDataContext context = DataContextFactory.GetDataContext(); Query query = new Query(); //条件 query.AddCriteria("Name", "%yan", CriteriaOperator.Like); query.AddCriteria("IsDelete",true,CriteriaOperator.NotEq); //排序 query.AddOrderClause("CreateTime", false); query.AddOrderClause(new OrderClause() { ascending = true, PropertyName = "ID" }); //根据条件查询 IList<User> users= context.GetByCriteria<User>(query); foreach (User user in users) { Console.WriteLine("id:{0} name:{1}", user.ID, user.Name); Console.WriteLine("department:{0}",user.Department.Name);//延迟加载 } }
id:11 name:yan
department:mydept
id:10 name:13yan
department:mydept
上面的例子已经可以看到,统一的上下文能够支持条件查询和延迟加载。可以看出我使用的是那种ORM吗?
分页
[Test] public void PageListTest() { Query query = new Query(); query.AddCriteria("IsDelete", true, CriteriaOperator.NotEq); query.AddOrderClause("ID", true); IDataContext context = DataContextFactory.GetDataContext(); IList<User> users = context.GetByCriteria<User>(query,0, 10); int count = context.GetCount<User>(query); foreach (User user in users) { Console.WriteLine("id:{0} name:{1}", user.ID, user.Name); } Console.WriteLine("sum:{0}",count); }
id:1 name:lucy
id:3 name:Lily
id:9 name:nddd
id:10 name:13yan
id:11 name:yan
id:41 name:adama3
sum:6
非工作单元
在非工作单元的事务中,Add之后立即写入了数据库,可以看到user1已经写入数据库,并且持久化了。
工作单元
在工作单元的事务中,只要没有Commit(),新增对象的任务只是被暂存起来,到提交时一并执行。可以发现Add之后并没有写入数据库和持久化。
小结:中午时间真是短暂,时间关系就先写到这里吧,有兴趣再接下去分析。