前言
关于EF5中使用UnitWork,参见另一博文: https://www.cnblogs.com/masonblog/p/9801162.html
每次提交数据库都会打开一个连接,造成结果是:多个连接无法共用一个数据库级别的事务,也就无法保证数据的原子性、一致性。
解决办法是:在ObjectContext的CRUD操作基础上再包装一层,提供统一的入口,让服务层调用。
同一个UnitOfWork实例对象下所有的ObjectContext都共同一个数据库上下文对象(ps:EF用的是ObjectContext),也就是共用一个事物。
提交数据库时,只要有一个操作失败,那么所有的操作都被视为失败。
实际使用:https://www.cnblogs.com/masonblog/p/9563199.html
代码托管:https://github.com/catbiscuit/AutofacStudy
实现过程
实体层
删除其中的两个.tt文件,然后在edmx页面,右键点击属性,将属性中的代码生成策略 从"无"修改为"默认值"。
数据访问层
Teacher表示例
IDAL层
直接继承IDALBase<T>泛型接口,其中定义了一些基础的方法。
namespace Apps.IDAL { public interface ITeacherDAL : IDALBase<Teacher> { } }
DAL层
直接继承DALBase<T>类,和ITeacherDAL接口。
DALBase类,需要提供实体类和数据库上下文。因为需要创建一个统一管理数据库操作的对象。
namespace Apps.DAL { public class TeacherDAL : DALBase<Teacher, AutofacDBEntities>, ITeacherDAL { public TeacherDAL(IDatabaseFactory<AutofacDBEntities> databaseFactory) : base(databaseFactory) { } } }
IBLL层
定义基本的数据操作方法。
namespace Apps.IBLL { public interface ITeacherBLL { bool Add(Teacher entity); bool Delete(Teacher entity); bool Update(); Teacher GetModelByCondition(Expression<Func<Teacher, bool>> predicate); IQueryable<Teacher> GetList(Expression<Func<Teacher, bool>> predicate, Expression<Func<Teacher, object>> orderBy, bool isAscending); IQueryable<Teacher> GetList(Expression<Func<Teacher, bool>> predicate); Teacher GetModelBySql(string sql); } }
BLL层
对ITeacherBLL接口中方法的实现。
namespace Apps.BLL { public class TeacherBLL : ITeacherBLL { private readonly ITeacherDAL _iTeacherDAL; private readonly IUnitOfWork<AutofacDBEntities> _uwork; public TeacherBLL(ITeacherDAL iTeacherDAL , IUnitOfWork<AutofacDBEntities> uwork) { this._iTeacherDAL = iTeacherDAL; this._uwork = uwork; } public bool Add(Teacher entity) { _iTeacherDAL.Add(entity); return _uwork.Commit() > 0; } public bool Delete(Teacher entity) { _iTeacherDAL.Delete(entity); return _uwork.Commit() > 0; } public bool Update() { return _uwork.Commit() > 0; } public Teacher GetModelByCondition(Expression<Func<Teacher, bool>> predicate) { return _iTeacherDAL.GetModelByCondition(predicate); } public IQueryable<Teacher> GetList(Expression<Func<Teacher, bool>> predicate , Expression<Func<Teacher, object>> orderBy , bool isAscending) { return _iTeacherDAL.GetList(predicate, orderBy, isAscending); } public IQueryable<Teacher> GetList(Expression<Func<Teacher, bool>> predicate) { return _iTeacherDAL.GetList(predicate); } public Teacher GetModelBySql(string sql) { return _iTeacherDAL.GetModelBySql(sql); } } }
注意
第一:类中定义了一个IUnitOfWork泛型对象,这个就是单元事务的管理对象。
DAL层只是将对数据的操作,添加到一个数据缓存的集合中。
当数据操作的步骤完成时,才调用IUnitOfWork泛型对象进行数据操作的提交。
这样确保了原子性和一致性。
第二:Update操作,BLL并没有将数据的操作添加到数据缓存的集合中。
此处,可以通过单步调试,当执行到UnitOfWork类中时,
监视DbContext对象的值,这个对象会监视数据库上下文中数据的状态。
这个地方,就要求Update操作的对象只能是从数据库获取得来。
使用lambda表达式获取实体。
示例操作:
Model model = DAL.GetModel(2);
model.Name = "修改Name";
BLL.Update();
此时BLL层执行update方法,实际上只是执行了单元事务的提交,也就完成了对该条记录的修改。
但是,如果是实例化的对象是无法修改数据。
Model model = new Model();
model.ID = 2;
model.Name = "修改Name";
BLL.Update();
这样执行更新操作,是无法修改数据的
总结
DAL层,只是将数据的操作(新增修改删除)附加到数据库上下文中。
UnitOfWork,才是将数据进行提交的地方。
所以,BLL层的方法才能实现对数据的完成操作。