数据访问层的设计(一)——功能与接口定义

数据访问层的设计我研究了很长时间,关于接口的定义,好几次都推翻重来。

园子看到过很多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}\tname:{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}\tname:{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之后并没有写入数据库和持久化。

 

小结:中午时间真是短暂,时间关系就先写到这里吧,有兴趣再接下去分析。


<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值