ASP.NET MVC系列 框架搭建(二)之仓储层的优化
大神勿喷,小神默默学。
会了就是不值一提的东西,不会就是绝对的高大上。
最后上传源码。希望能给读者带来一些新的认识及知识。
还没上过头条。。各位大神,请点支持一下小弟。
陆续更新。更新到你会为止!!
我不是话唠,我只把重点点出来,细枝末节的不懂的可以留言探讨。这个系列的最后,我会再统一的把大家的问题,列在一篇新的Blog。工作需要规划,写博客也是如此。
需求
①请保持EF上下文的线程唯一。防止脏临时数据的出现
②请对程序扩展性做好设计。以后ef框架可能改为Spring框架
③服务层调用仓储层时。DBContext为统一入口
③.1 方便程序员开发,提供统一入口。把ef封装到此入口里面。
③.2防止脏临时数据的出现,“也”请保持这个入口的线程内唯一。
③.3要这个统一入口去除服务层和仓储层的耦合
思路
①把ef放进CallContext内。键值对形式存放。
②面向接口的思想
新建一个工厂接口+工厂。用一个“工厂方法”模式,非“简单工厂”,也非“抽象工厂”设计模式。如果您对工厂的几个设计模式不了解,请参考我写过的设计模式一篇blog。
③ ③.1新建一个类,命名DBContact里面的一个属性类型为ObjectContext,因为上下文继承ObjectContext,继而“点”多个仓储。
③.2放进CallContext内。键值对存储。
③.3新建一个IDBContact接口,让DBContact继承。用一个工厂继承一个接口工厂创建。“工厂方法”设计模式
思想
面向接口+工厂模式+线程唯一 2个抽象方法工厂作用:线程唯一+扩展性(面向接口)
详情代码
ISingleEFCntextFactory.cs
using System.Data.Objects; namespace LKBS.CommunicationPlatform.IDAL { public interface ISingleEFCntextFactory {//no public ObjectContext GetCurrentEFContext(); } }
SingleEFCntextFactory.cs
using LKBS.CommunicationPlatform.IDAL; using System.Data.Objects;//添加引用 System.Data.Entity using System.Runtime.Remoting.Messaging; using LKBS.CommunicationPlatform.Model; namespace LKBS.CommunicationPlatform.Factory { public class SingleEFCntextFactory : ISingleEFCntextFactory { public ObjectContext GetCurrentEFContext() { //把上下文(基类)放在一个线程内。让一次请求(一个ACTION)可能执行CRUD中的几步,公用一个上下文. ObjectContext callEFContext = (ObjectContext)CallContext.GetData("efContext");//线程槽 存放“键值对” //先读后写。没有就new一个上下文 if (callEFContext == null) { callEFContext = new ModelContainer(); } CallContext.SetData("efContext", callEFContext); return callEFContext; } } }
BaseRespository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using LKBS.CommunicationPlatform.Model; using LKBS.CommunicationPlatform.IDAL; using System.Data; using LKBS.CommunicationPlatform.Factory; using System.Data.Objects; namespace LKBS.CommunicationPlatform.DAL { public class BaseRespository<T> where T : class,new() { ISingleEFCntextFactory singleEFFactory = new SingleEFCntextFactory(); //中间加一个工厂,这里“去除”ef和具体仓储的耦合。可以更换ef。而Respositiry db不用变 ObjectContext db;//如果没赋值,那就是赋值的问题。找对应赋值的工厂 或者工厂还没编译 public BaseRespository() { ObjectContext db = singleEFFactory.GetCurrentEFContext(); } //ModelContainer db = efFactory.GetCurrentEFContext(); //字段初始值无法引用非静态字段、方法或属性. //那我们在构造方法内赋值 ....CRUD } }
为方便业务逻辑层调用,建立统一入口。
IDBContact.cs
using System.Data.Objects;//上下文在的空间 namespace LKBS.CommunicationPlatform.IDAL { public interface IDBContact { //接口中的属性要{} ObjectContext currentEFContext { get; set; } IUserInforRespository userinforResponsity { get; set; } //...多个其他表的仓储,在T4模板中加OK } }
DBContact.cs
using LKBS.CommunicationPlatform.IDAL; using System.Data.Objects;//上下文的命名空间 using LKBS.CommunicationPlatform.Factory; namespace LKBS.CommunicationPlatform.DAL { public class DBContact : IDBContact { public ObjectContext currentEFContext { get; set; } ISingleEFCntextFactory singleEFCntextFactory = new SingleEFCntextFactory();//SingleEFCntextFactory做到单一上下文 public DBContact() { currentEFContext = singleEFCntextFactory.GetCurrentEFContext();// } public IUserInforRespository userinforResponsity { get; set; } } }
ISingleDBContactFactory.cs
namespace LKBS.CommunicationPlatform.IDAL { public interface ISingleDBContactFactory { IDBContact CreateDBCotactUseEF(); } }
SingleDBContactFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using LKBS.CommunicationPlatform.IDAL; using System.Data.Objects; using System.Runtime.Remoting.Messaging; using LKBS.CommunicationPlatform.DAL; namespace LKBS.CommunicationPlatform.Factory { //继承接口①接口要编译过,②引入接口所用的程序集+ using class SingleDBContactFactory : ISingleDBContactFactory { public IDBContact CreateDBCotactUseEF() { //ObjectContext currentEFContext = new ObjectContext("currentEFContext"); //return currentEFContext; IDBContact dbCotact = (DBContact)CallContext.GetData("currentDBContact"); if (dbCotact==null) { dbCotact = new DBContact(); } CallContext.SetData("currentDBContact", dbCotact); return dbCotact; } } }