您好,欢迎访问一九零五行业门户网

总结EF通用数据层封装类实例详解

浅谈orm记得四年前在学校第一次接触到 ling to sql,那时候瞬间发现不用手写sql语句是多么的方便,后面慢慢的接触了许多orm框架,像 ef,dapper,hibernate,servicestack.ormlite 等。当然每种orm都有各自的优势,也有不足的地方。园子里也有很多大神开源了他们写的orm,如sqlsugar,chloe.orm,cyq.data 等。先不说这些开源的orm使用度怎么样,我觉得起码从开源的精神上就很可嘉了,我也曾下载过这几位大神的源码进行学习。
所有orm最终体现的一点就是方便,减少程序员重复性的工作,当然目前还有一些公司还是使用手写sql的方式来做,我觉得整个项目都使用手写sql来做真的是有点闲到蛋疼,并不是不推荐手写sql的方式,只是个人觉得最基本的增删改查这些都手写的话,那其实考验不是能力,而是耐力。有人说手写sql的方式可控性强,性能高,我想说的是orm也能做到,关键是你怎么去使用。
orm的优点非常明显,开发便捷,但或许也是由于这个优点,让很多偷懒的程序员也会渐渐忘了sql语句的写法,我遇到过很多的程序员朋友用了ef后,手写sql,视图、存储过程这些都不想用了,我个人觉手写sql这种还是必要的。不然某一天你看到别人的程序里面写着 “exec  xxxx”,你就会突然觉得“啊,好像在哪里见过.....”。所以我想说的是“该出手时还是得出手。
浅谈entity frameworkentity framework 是微软家的orm框架,随着 entity framework 不断的完善强化,目前相信使用的比例相对其他的orm来说还是较高的。像我目前使用的最多的就是ef和dapper。确实,ef用起来开发过程中会方便很多,毕竟ef走过了这么年头,无论是成熟度,还是性能等都提高了很多,也有很多开发者为ef提供了扩展功能,如entity framework extended 等。而且作为.net开发者来说项目通用性也很强,资料也多,微软在这块的更新力度也很给力。不过之前刚出的ef core也存在一些坑,毕竟还是初期阶段,相信现在后面会越来越好的。
entity framework  提供了三种开发模式,code first,db first,model first。目前用的最多的就属code first了。至于这三种模式的简单使用和区别,大家可以参考下这篇文章。
我曾听一些朋友说过说ef使用起来性能很差,生成的sql语句很难看等。我觉得说这种话之前还是先检查下代码或者多看下一些ef文章吧,要先确保自己没给自己挖坑,然后才能指责别人的不好。如果真心觉得ef或者其他的orm用起来很不爽,那就自己写一个吧,我也曾经和同事用dapper扩展一个通用的orm,当时是出于一种学习和使用方便的角度。
entity framework 通用数据层类这里提供下 ef 通用数据层父类方法,其实网上也有很多人提供了自己项目中的 ef 通用数据层父类方法,所以这里提供的并不是最优和最好的选择,只能说是可以通用的类,方便大家学习和使用,具体代码如下:
dbcontextfactory dbcontext工厂类    public class dbcontextfactory     {public  dbcontext getdbcontext()         {string key = typeof(dbcontext.dbcontextfactory).name + xjhdbcontext;             dbcontext dbcontext = callcontext.getdata(key) as dbcontext;if (dbcontext == null)             {                 dbcontext = new xjhdbcontext();                 callcontext.setdata(key, dbcontext);             }return dbcontext;         }     }
dbbase 数据层通用操作类 public class dbbase     {protected dbcontext db = new dbcontextfactory().getdbcontext();        #region 自定义其他方法/// <summary>/// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public list<tmodel> query<tmodel>(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {//存储过程(exec getactionurlid @name,@id)if (cmdtype == commandtype.storedprocedure)             {                 stringbuilder paranames = new stringbuilder();foreach (var sqlpara in parms)                 {                     paranames.append($ @{sqlpara},);                 }                 sql = paranames.length > 0 ? $exec {sql} {paranames.tostring().trim(',')} : $exec {sql} ;             }var list = db.database.sqlquery<tmodel>(sql, parms.toarray());var enitylist = list.tolist();return enitylist;         }/// <summary>/// 自定义语句和存储过程的增删改--返回影响的行数/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public int execute(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {//存储过程(exec getactionurlid @name,@id)if (cmdtype == commandtype.storedprocedure)             {                 stringbuilder paranames = new stringbuilder();foreach (var sqlpara in parms)                 {                     paranames.append($ @{sqlpara},);                 }                 sql = paranames.length > 0 ?$exec {sql} {paranames.tostring().trim(',')} :                     $exec {sql} ;             }int ret = db.database.executesqlcommand(sql, parms.toarray());return ret;         }#endregion 自定义其他方法}/// <summary>/// mssql数据库 数据层 父类/// </summary>/// <typeparam name="t"></typeparam>public class dbbase<t> : dbbase where t : class, new()     {#region insert/// <summary>/// 新增 实体/// </summary>/// <param name="model"></param>/// <returns></returns>public void insert(t model)         {             db.set<t>().add(model);         }/// <summary>/// 普通批量插入/// </summary>/// <param name="datas"></param>public void insertrange(list<t> datas)         {             db.set<t>().addrange(datas);         }#endregion insert#region delete/// <summary>/// 根据模型删除/// </summary>/// <param name="model">包含要删除id的对象</param>/// <returns></returns>public void delete(t model)         {             db.set<t>().attach(model);             db.set<t>().remove(model);         }/// <summary>/// 删除/// </summary>/// <param name="wherelambda"></param>public void delete(expression<func<t, bool>> wherelambda)         {             db.set<t>().where(wherelambda).delete();         }#endregion delete#region update/// <summary>/// 单个对象指定列修改/// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="pronames">要修改的 属性 名称</param>/// <param name="isproupdate"></param>/// <returns></returns>public void update(t model, list<string> pronames, bool isproupdate = true)         {//将 对象 添加到 ef中db.set<t>().attach(model);var setentry = ((iobjectcontextadapter)db).objectcontext.objectstatemanager.getobjectstateentry(model);//指定列修改if (isproupdate)             {foreach (string proname in pronames)                 {                     setentry.setmodifiedproperty(proname);                 }             }//忽略类修改else{                 type t = typeof(t);                 list<propertyinfo> proinfos = t.getproperties(bindingflags.instance | bindingflags.public).tolist();foreach (var item in proinfos)                 {string proname = item.name;if (pronames.contains(proname))                     {continue;                     }                     setentry.setmodifiedproperty(proname);                 }             }         }/// <summary>/// 单个对象修改/// </summary>/// <param name="model"></param>/// <returns></returns>public void update(t model)         {             dbentityentry entry = db.entry<t>(model);             db.set<t>().attach(model);             entry.state = entitystate.modified;         }/// <summary>/// 批量修改/// </summary>/// <param name="wherelambda"></param>/// <param name="updateexpression"></param>public void update(expression<func<t, bool>> wherelambda, expression<func<t, t>> updateexpression)         {             db.set<t>().where(wherelambda).update(updateexpression);         }/// <summary>/// 批量修改/// </summary>/// <param name="models"></param>/// <returns></returns>public void updateall(list<t> models)         {foreach (var model in models)             {                 dbentityentry entry = db.entry(model);                 entry.state = entitystate.modified;             }         }/// <summary>/// 批量统一修改/// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="wherelambda">查询条件</param>/// <param name="modifiedpronames"></param>/// <returns></returns>public void update(t model, expression<func<t, bool>> wherelambda, params string[] modifiedpronames)         {//查询要修改的数据list<t> listmodifing = db.set<t>().where(wherelambda).tolist();             type t = typeof(t);             list<propertyinfo> proinfos = t.getproperties(bindingflags.instance | bindingflags.public).tolist();             dictionary<string, propertyinfo> dictpros = new dictionary<string, propertyinfo>();             proinfos.foreach(p =>{if (modifiedpronames.contains(p.name))                 {                     dictpros.add(p.name, p);                 }             });if (dictpros.count  wherelambda = null)         {if (wherelambda == null)             {return db.set<t>().firstordefault();             }return db.set<t>().firstordefault(wherelambda);         }/// <summary>/// 获取全部数据/// </summary>/// <returns></returns>public list<t> getall(string ordering = null)         {return ordering == null? db.set<t>().tolist()                 : db.set<t>().orderby(ordering).tolist();         }/// <summary>/// 带条件查询获取数据/// </summary>/// <param name="wherelambda"></param>/// <param name="ordering"></param>/// <returns></returns>public list<t> getall(expression<func<t, bool>> wherelambda, string ordering = null)         {var iqueryable = db.set<t>().where(wherelambda);return ordering == null? iqueryable.tolist()                 : iqueryable.orderby(ordering).tolist();         }/// <summary>/// 带条件查询获取数据/// </summary>/// <param name="wherelambda"></param>/// <returns></returns>public iqueryable<t> getalliqueryable(expression<func<t, bool>> wherelambda = null)         {return wherelambda == null ? db.set<t>() : db.set<t>().where(wherelambda);         }/// <summary>/// 获取数量/// </summary>/// <param name="wherelambd"></param>/// <returns></returns>public int getcount(expression<func<t, bool>> wherelambd = null)         {return wherelambd == null ? db.set<t>().count() : db.set<t>().where(wherelambd).count();         }/// <summary>/// 判断对象是否存在/// </summary>/// <param name="wherelambd"></param>/// <returns></returns>public bool any(expression<func<t, bool>> wherelambd)         {return db.set<t>().where(wherelambd).any();         }/// <summary>/// 分页查询/// </summary>/// <param name="pageindex">当前页码</param>/// <param name="pagesize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="orderby">排序条件(一定要有)</param>/// <param name="wherelambda">查询添加(可有,可无)</param>/// <param name="isorder">是否是order排序</param>/// <returns></returns>public list<t> page<tkey>(int pageindex, int pagesize, out int rows, expression<func<t, tkey>> orderby, expression<func<t, bool>> wherelambda = null, bool isorder = true)         {             iqueryable<t> data = isorder ?db.set<t>().orderby(orderby) :                 db.set<t>().orderbydescending(orderby);if (wherelambda != null)             {                 data = data.where(wherelambda);             }             rows = data.count();return data.pageby((pageindex - 1) * pagesize, pagesize).tolist();         }/// <summary>/// 分页查询/// </summary>/// <param name="pageindex">当前页码</param>/// <param name="pagesize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="ordering">排序条件(一定要有)</param>/// <param name="wherelambda">查询添加(可有,可无)</param>/// <returns></returns>public list<t> page(int pageindex, int pagesize, out int rows, string ordering, expression<func<t, bool>> wherelambda = null)         {// 分页 一定注意: skip 之前一定要 orderbyvar data = db.set<t>().orderby(ordering);if (wherelambda != null)             {                 data = data.where(wherelambda);             }             rows = data.count();return data.pageby((pageindex - 1) * pagesize, pagesize).tolist();         }/// <summary>/// 查询转换/// </summary>/// <typeparam name="tdto"></typeparam>/// <param name="wherelambda"></param>/// <returns></returns>public list<tdto> select<tdto>(expression<func<t, bool>> wherelambda)         {return db.set<t>().where(wherelambda).select<tdto>().tolist();         }#endregion select#region orther/// <summary>/// 执行存储过程或自定义sql语句--返回集合/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public list<t> query(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {return query<t>(sql, parms, cmdtype);         }/// <summary>/// 提交保存/// </summary>/// <returns></returns>public int savechanges()         {return db.savechanges();         }/// <summary>/// 回滚/// </summary>public void rollbackchanges()         {var items = db.changetracker.entries().tolist();             items.foreach(o => o.state = entitystate.unchanged);         }#endregion orther}
dbbase
扩展类,实现读写分离上面的通用类是比较基础简单通用的,适合于单库读写操作。对于ef实现读写分离,之前网上找过类似的参考文章,很多人文章都是使用 dbcommandinterceptor拦截器 来实现,具体的做法是通过拦截到sql语句,然后根据具体条件去判断是走主库还是从库。这种做法不是不行,只是个人感觉不是很好扩展,而且要在拦截器里面做限制判断。
其实说白了ef本身就是一个读写分离的orm。用过ef的人知道,ef提供访问数据库的是 dbcontext 这个对象,所以想实现读写分离的就很简单了,只要在程序中使用两个不同的dbcontext对象,一个负责读,一个负责写就好了。
所以在上面提供的通用封装类中稍微做下修改,修改如下dbcontextfactory中获取dbcontext的方法,实现一个读的dbcontext和一个写的dbcontext对象的获取。
这里要注意下,对于读的dbcontext来说,要做下设置
1.使用 database.setinitializer(new nulldatabaseinitializer<readdbcontext>()); 改变ef初始化策略,因为一般我们使用读写分离的话从库都是同步于主库的,所以不使用ef的自动创建数据库策略。
2.重写 savechanges 方法,对应从库来说,只提供读取的功能,所以防止误操作,这里禁用掉savechanges方法,一般需要使用从读的保存方法,就对外抛出异常。
代码如下:
支持读写分离的 dbcontextfactory 类  public class dbcontextfactory     {public dbcontext getwritedbcontext(){string key = typeof(dbcontextfactory).name + writedbcontext;             dbcontext dbcontext = callcontext.getdata(key) as dbcontext;if (dbcontext == null)             {                 dbcontext = new writedbcontext();                 callcontext.setdata(key, dbcontext);             }return dbcontext;         }public dbcontext getreaddbcontext(){string key = typeof(dbcontextfactory).name + readdbcontext;             dbcontext dbcontext = callcontext.getdata(key) as dbcontext;if (dbcontext == null)             {                 dbcontext = new readdbcontext();                 callcontext.setdata(key, dbcontext);             }return dbcontext;         }     }
对应的 dbbase 类也做下修改,主要将上面的db对象改作 masterdb 和 slavedb 对象,并且把上面的读写方法坐下调整,修改后如下:
支持读写分离的 dbbase类public class dbbase     {//是否读写分离(可以配置在配置文件中)private static readonly bool isreadwriteseparation = true;#region ef上下文对象(主库)protected dbcontext masterdb => _masterdb.value;private readonly lazy<dbcontext> _masterdb = new lazy<dbcontext>(() => new dbcontextfactory().getwritedbcontext());#endregion ef上下文对象(主库)#region ef上下文对象(从库)protected dbcontext slavedb => isreadwriteseparation ? _slavedb.value : _masterdb.value;private readonly lazy<dbcontext> _slavedb = new lazy<dbcontext>(() => new dbcontextfactory().getreaddbcontext());#endregion ef上下文对象(从库)#region 自定义其他方法/// <summary>/// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public list<tmodel> query<tmodel>(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {//存储过程(exec getactionurlid @name,@id)if (cmdtype == commandtype.storedprocedure)             {                 stringbuilder paranames = new stringbuilder();foreach (var sqlpara in parms)                 {                     paranames.append($ @{sqlpara},);                 }                 sql = paranames.length > 0 ? $exec {sql} {paranames.tostring().trim(',')} : $exec {sql} ;             }var list = slavedb.database.sqlquery<tmodel>(sql, parms.toarray());var enitylist = list.tolist();return enitylist;         }/// <summary>/// 自定义语句和存储过程的增删改--返回影响的行数/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public int execute(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {//存储过程(exec getactionurlid @name,@id)if (cmdtype == commandtype.storedprocedure)             {                 stringbuilder paranames = new stringbuilder();foreach (var sqlpara in parms)                 {                     paranames.append($ @{sqlpara},);                 }                 sql = paranames.length > 0 ?$exec {sql} {paranames.tostring().trim(',')} :                     $exec {sql} ;             }int ret = masterdb.database.executesqlcommand(sql, parms.toarray());return ret;         }#endregion 自定义其他方法}/// <summary>/// mssql数据库 数据层 父类/// </summary>/// <typeparam name="t"></typeparam>public class dbbase<t> : dbbase where t : class, new()     {#region insert/// <summary>/// 新增 实体/// </summary>/// <param name="model"></param>/// <returns></returns>public void insert(t model)         {             masterdb.set<t>().add(model);         }/// <summary>/// 普通批量插入/// </summary>/// <param name="datas"></param>public void insertrange(list<t> datas)         {             masterdb.set<t>().addrange(datas);         }#endregion insert#region delete/// <summary>/// 根据模型删除/// </summary>/// <param name="model">包含要删除id的对象</param>/// <returns></returns>public void delete(t model)         {             masterdb.set<t>().attach(model);             masterdb.set<t>().remove(model);         }/// <summary>/// 删除/// </summary>/// <param name="wherelambda"></param>public void delete(expression<func<t, bool>> wherelambda)         {             masterdb.set<t>().where(wherelambda).delete();         }#endregion delete#region update/// <summary>/// 单个对象指定列修改/// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="pronames">要修改的 属性 名称</param>/// <param name="isproupdate"></param>/// <returns></returns>public void update(t model, list<string> pronames, bool isproupdate = true)         {//将 对象 添加到 ef中masterdb.set<t>().attach(model);var setentry = ((iobjectcontextadapter)masterdb).objectcontext.objectstatemanager.getobjectstateentry(model);//指定列修改if (isproupdate)             {foreach (string proname in pronames)                 {                     setentry.setmodifiedproperty(proname);                 }             }//忽略类修改else{                 type t = typeof(t);                 list<propertyinfo> proinfos = t.getproperties(bindingflags.instance | bindingflags.public).tolist();foreach (var item in proinfos)                 {string proname = item.name;if (pronames.contains(proname))                     {continue;                     }                     setentry.setmodifiedproperty(proname);                 }             }         }/// <summary>/// 单个对象修改/// </summary>/// <param name="model"></param>/// <returns></returns>public void update(t model)         {             dbentityentry entry = masterdb.entry<t>(model);             masterdb.set<t>().attach(model);             entry.state = entitystate.modified;         }/// <summary>/// 批量修改/// </summary>/// <param name="wherelambda"></param>/// <param name="updateexpression"></param>public void update(expression<func<t, bool>> wherelambda, expression<func<t, t>> updateexpression)         {             masterdb.set<t>().where(wherelambda).update(updateexpression);         }/// <summary>/// 批量修改/// </summary>/// <param name="models"></param>/// <returns></returns>public void updateall(list<t> models)         {foreach (var model in models)             {                 dbentityentry entry = masterdb.entry(model);                 entry.state = entitystate.modified;             }         }/// <summary>/// 批量统一修改/// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="wherelambda">查询条件</param>/// <param name="modifiedpronames"></param>/// <returns></returns>public void update(t model, expression<func<t, bool>> wherelambda, params string[] modifiedpronames)         {//查询要修改的数据list<t> listmodifing = masterdb.set<t>().where(wherelambda).tolist();             type t = typeof(t);             list<propertyinfo> proinfos = t.getproperties(bindingflags.instance | bindingflags.public).tolist();             dictionary<string, propertyinfo> dictpros = new dictionary<string, propertyinfo>();             proinfos.foreach(p =>{if (modifiedpronames.contains(p.name))                 {                     dictpros.add(p.name, p);                 }             });if (dictpros.count  wherelambda = null)         {if (wherelambda == null)             {return slavedb.set<t>().firstordefault();             }return slavedb.set<t>().firstordefault(wherelambda);         }/// <summary>/// 获取全部数据/// </summary>/// <returns></returns>public list<t> getall(string ordering = null)         {return ordering == null? slavedb.set<t>().tolist()                 : slavedb.set<t>().orderby(ordering).tolist();         }/// <summary>/// 带条件查询获取数据/// </summary>/// <param name="wherelambda"></param>/// <param name="ordering"></param>/// <returns></returns>public list<t> getall(expression<func<t, bool>> wherelambda, string ordering = null)         {var iqueryable = slavedb.set<t>().where(wherelambda);return ordering == null? iqueryable.tolist()                 : iqueryable.orderby(ordering).tolist();         }/// <summary>/// 带条件查询获取数据/// </summary>/// <param name="wherelambda"></param>/// <returns></returns>public iqueryable<t> getalliqueryable(expression<func<t, bool>> wherelambda = null)         {return wherelambda == null ? slavedb.set<t>() : slavedb.set<t>().where(wherelambda);         }/// <summary>/// 获取数量/// </summary>/// <param name="wherelambd"></param>/// <returns></returns>public int getcount(expression<func<t, bool>> wherelambd = null)         {return wherelambd == null ? slavedb.set<t>().count() : slavedb.set<t>().where(wherelambd).count();         }/// <summary>/// 判断对象是否存在/// </summary>/// <param name="wherelambd"></param>/// <returns></returns>public bool any(expression<func<t, bool>> wherelambd)         {return slavedb.set<t>().where(wherelambd).any();         }/// <summary>/// 分页查询/// </summary>/// <param name="pageindex">当前页码</param>/// <param name="pagesize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="orderby">排序条件(一定要有)</param>/// <param name="wherelambda">查询添加(可有,可无)</param>/// <param name="isorder">是否是order排序</param>/// <returns></returns>public list<t> page<tkey>(int pageindex, int pagesize, out int rows, expression<func<t, tkey>> orderby, expression<func<t, bool>> wherelambda = null, bool isorder = true)         {             iqueryable<t> data = isorder ?slavedb.set<t>().orderby(orderby) :                 slavedb.set<t>().orderbydescending(orderby);if (wherelambda != null)             {                 data = data.where(wherelambda);             }             rows = data.count();return data.pageby((pageindex - 1) * pagesize, pagesize).tolist();         }/// <summary>/// 分页查询/// </summary>/// <param name="pageindex">当前页码</param>/// <param name="pagesize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="ordering">排序条件(一定要有)</param>/// <param name="wherelambda">查询添加(可有,可无)</param>/// <returns></returns>public list<t> page(int pageindex, int pagesize, out int rows, string ordering, expression<func<t, bool>> wherelambda = null)         {// 分页 一定注意: skip 之前一定要 orderbyvar data = slavedb.set<t>().orderby(ordering);if (wherelambda != null)             {                 data = data.where(wherelambda);             }             rows = data.count();return data.pageby((pageindex - 1) * pagesize, pagesize).tolist();         }/// <summary>/// 查询转换/// </summary>/// <typeparam name="tdto"></typeparam>/// <param name="wherelambda"></param>/// <returns></returns>public list<tdto> select<tdto>(expression<func<t, bool>> wherelambda)         {return slavedb.set<t>().where(wherelambda).select<tdto>().tolist();         }#endregion select#region orther/// <summary>/// 执行存储过程或自定义sql语句--返回集合/// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdtype"></param>/// <returns></returns>public list<t> query(string sql, list<sqlparameter> parms, commandtype cmdtype = commandtype.text)         {return query<t>(sql, parms, cmdtype);         }/// <summary>/// 提交保存/// </summary>/// <returns></returns>public int savechanges()         {return masterdb.savechanges();         }/// <summary>/// 回滚/// </summary>public void rollbackchanges()         {var items = masterdb.changetracker.entries().tolist();             items.foreach(o => o.state = entitystate.unchanged);         }#endregion orther}
dbbase
这样简单的读写分离就实现了,实现逻辑也比较清晰,方便扩展。
进一步改造,实现多从库读取一般做读写分离,都会做一主多从,特别对读取量比较大的项目,这样多库读取就能减轻读库的压力。所以对于上面的方法,做下改造。
上面可以看到,主库和从库都是通过 dbcontextfactory 这个类来获取的,在getreaddbcontext 方法中每次都是获取 readdbcontext 这个对象。那么对于多个从库的情况下,每次读取到底要去哪个库读取数据呢?这里就是一个算法规则的问题了,或者说是策略吧,如果使用过nginx的朋友就知道,nginx本身内部在实现负载均衡的时候提供了多种策略,比如轮询,加权轮询,ip_hash等策略。其实上面获取同一个readdbcontext 的方法也算一种策略,叫单一策略,每次都获取单一的对象。
多从库的情况下,我们简单的来实现另一种获取策略,随机策略,每次都随机获取到一个从库的对象,这种是最简单的策略,当然,正式使用的话大家可以发挥自己的创造力,写出多了的算法策略。
首先,定义一个策略接口,方便策略的扩展和切换,代码如下:
ireaddbstrategy 接口 /// <summary>   /// 从数据库获取策略接口  /// </summary>   public interface ireaddbstrategy   {      /// <summary>  /// 获取读库      /// </summary>  /// <returns></returns>      dbcontext getdbcontext();   }
单从库情况下,定义一个单一策略,代码如下:
单一策略   /// <summary>    /// 单一策略   /// </summary>    public class singlestrategy : ireaddbstrategy    {       public dbcontext getdbcontext()        {           return new readdbcontext();        }    }
多从库情况下,定义一个随机策略,代码如下:
随机策略    /// <summary>/// 随机策略/// </summary>public class randomstrategy : ireaddbstrategy     {//所有读库类型public static list<type> dbtypes; static randomstrategy()         {             loaddbs();         } //加载所有的读库类型static void loaddbs()         {             dbtypes = new list<type>();var assembly = assembly.getexecutingassembly();var types = assembly.gettypes();foreach (var type in types)             {if (type.basetype == typeof(basereaddbcontext))                 {                     dbtypes.add(type);                 }             }         } public dbcontext getdbcontext()         {int randomindex = new random().next(0, dbtypes.count);var dbtype = dbtypes[randomindex];var dbcontext = activator.createinstance(dbtype) as dbcontext;return dbcontext;         }     }
这样,所有从库我们都基于策略去获取,扩展也比较方便。修改下 dbcontextfactory 类的 getreaddbcontext 方法,通过策略接口来获取,代码如下:
支持一主多从的 dbcontextfactory 类  public class dbcontextfactory     {//todo:这里可以自己通过注入的方式来实现,就会更加灵活private static readonly ireaddbstrategy readdbstrategy = new randomstrategy();public dbcontext getwritedbcontext()         {string key = typeof(dbcontextfactory).name + writedbcontext;             dbcontext dbcontext = callcontext.getdata(key) as dbcontext;if (dbcontext == null)             {                 dbcontext = new writedbcontext();                 callcontext.setdata(key, dbcontext);             }return dbcontext;         }public dbcontext getreaddbcontext()         {string key = typeof(dbcontextfactory).name + readdbcontext;             dbcontext dbcontext = callcontext.getdata(key) as dbcontext;if (dbcontext == null)             {                 dbcontext = readdbstrategy.getdbcontext();callcontext.setdata(key, dbcontext);             }return dbcontext;         }     }
这样简单的一主多从也实现了。
参考文章
源码分享所有的代码提供给大家的更多的是一种思路和学习的参考,如果有什么不足的地方也欢迎大家批评指正,如果觉得对你有帮助,不要吝啬你的鼠标,帮忙点个星,点个赞吧。
以上就是总结ef通用数据层封装类实例详解的详细内容。
其它类似信息

推荐信息