前言
關於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層的方法才能實現對數據的完成操作。