0

0

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

零下一度

零下一度

发布时间:2017-06-24 09:54:43

|

4213人浏览过

|

来源于php中文网

原创

浅谈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 Framework

  entity 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 自定义其他方法/// /// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)/// /// /// /// /// public List Query(string sql, List 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(sql, parms.ToArray());var enityList = list.ToList();return enityList;
        }/// /// 自定义语句和存储过程的增删改--返回影响的行数/// /// /// /// /// public int Execute(string sql, List 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 自定义其他方法}/// /// mssql数据库 数据层 父类/// /// public class DbBase : DbBase where T : class, new()
    {#region INSERT/// /// 新增 实体/// /// /// public void Insert(T model)
        {
            Db.Set().Add(model);

        }/// /// 普通批量插入/// /// public void InsertRange(List datas)
        {
            Db.Set().AddRange(datas);
        }#endregion INSERT#region DELETE/// /// 根据模型删除/// /// 包含要删除id的对象/// public void Delete(T model)
        {
            Db.Set().Attach(model);
            Db.Set().Remove(model);
        }/// /// 删除/// /// public void Delete(Expression> whereLambda)
        {
            Db.Set().Where(whereLambda).Delete();
        }#endregion DELETE#region UPDATE/// /// 单个对象指定列修改/// /// 要修改的实体对象/// 要修改的 属性 名称/// /// public void Update(T model, List proNames, bool isProUpdate = true)
        {//将 对象 添加到 EF中Db.Set().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 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);
                }
            }
        }/// /// 单个对象修改/// /// /// public void Update(T model)
        {
            DbEntityEntry entry = Db.Entry(model);
            Db.Set().Attach(model);
            entry.State = EntityState.Modified;

        }/// /// 批量修改/// /// /// public void Update(Expression> whereLambda, Expression> updateExpression)
        {
            Db.Set().Where(whereLambda).Update(updateExpression);
        }/// /// 批量修改/// /// /// public void UpdateAll(List models)
        {foreach (var model in models)
            {
                DbEntityEntry entry = Db.Entry(model);
                entry.State = EntityState.Modified;
            }


        }/// /// 批量统一修改/// /// 要修改的实体对象/// 查询条件/// /// public void Update(T model, Expression> whereLambda, params string[] modifiedProNames)
        {//查询要修改的数据List listModifing = Db.Set().Where(whereLambda).ToList();
            Type t = typeof(T);
            List proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
            Dictionary dictPros = new Dictionary();
            proInfos.ForEach(p =>{if (modifiedProNames.Contains(p.Name))
                {
                    dictPros.Add(p.Name, p);
                }
            });if (dictPros.Count <= 0)
            {throw new Exception("指定修改的字段名称有误或为空");
            }foreach (var item in dictPros)
            {
                PropertyInfo proInfo = item.Value;//取出 要修改的值object newValue = proInfo.GetValue(model, null);//批量设置 要修改 对象的 属性foreach (T oModel in listModifing)
                {//为 要修改的对象 的 要修改的属性 设置新的值proInfo.SetValue(oModel, newValue, null);
                }
            }

        }#endregion UPDATE#region SELECT/// /// 根据主键查询/// /// /// public T FindById(dynamic id)
        {return Db.Set().Find(id);
        }/// /// 获取默认一条数据,没有则为NULL/// /// /// public T FirstOrDefault(Expression> whereLambda = null)
        {if (whereLambda == null)
            {return Db.Set().FirstOrDefault();
            }return Db.Set().FirstOrDefault(whereLambda);
        }/// /// 获取全部数据/// /// public List GetAll(string ordering = null)
        {return ordering == null? Db.Set().ToList()
                : Db.Set().OrderBy(ordering).ToList();
        }/// /// 带条件查询获取数据/// /// /// /// public List GetAll(Expression> whereLambda, string ordering = null)
        {var iQueryable = Db.Set().Where(whereLambda);return ordering == null? iQueryable.ToList()
                : iQueryable.OrderBy(ordering).ToList();
        }/// /// 带条件查询获取数据/// /// /// public IQueryable GetAllIQueryable(Expression> whereLambda = null)
        {return whereLambda == null ? Db.Set() : Db.Set().Where(whereLambda);
        }/// /// 获取数量/// /// /// public int GetCount(Expression> whereLambd = null)
        {return whereLambd == null ? Db.Set().Count() : Db.Set().Where(whereLambd).Count();
        }/// /// 判断对象是否存在/// /// /// public bool Any(Expression> whereLambd)
        {return Db.Set().Where(whereLambd).Any();
        }/// /// 分页查询/// /// 当前页码/// 每页大小/// 总条数/// 排序条件(一定要有)/// 查询添加(可有,可无)/// 是否是Order排序/// public List Page(int pageIndex, int pageSize, out int rows, Expression> orderBy, Expression> whereLambda = null, bool isOrder = true)
        {
            IQueryable data = isOrder ?Db.Set().OrderBy(orderBy) :
                Db.Set().OrderByDescending(orderBy);if (whereLambda != null)
            {
                data = data.Where(whereLambda);
            }
            rows = data.Count();return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();
        }/// /// 分页查询/// /// 当前页码/// 每页大小/// 总条数/// 排序条件(一定要有)/// 查询添加(可有,可无)/// public List Page(int pageIndex, int pageSize, out int rows, string ordering, Expression> whereLambda = null)
        {// 分页 一定注意: Skip 之前一定要 OrderByvar data = Db.Set().OrderBy(ordering);if (whereLambda != null)
            {
                data = data.Where(whereLambda);
            }
            rows = data.Count();return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();
        }/// /// 查询转换/// /// /// /// public List Select(Expression> whereLambda)
        {return Db.Set().Where(whereLambda).Select().ToList();
        }#endregion SELECT#region ORTHER/// /// 执行存储过程或自定义sql语句--返回集合/// /// /// /// /// public List Query(string sql, List parms, CommandType cmdType = CommandType.Text)
        {return Query(sql, parms, cmdType);
        }/// /// 提交保存/// /// public int SaveChanges()
        {return Db.SaveChanges();
        }/// /// 回滚/// 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()); 改变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 _masterDb = new Lazy(() => new DbContextFactory().GetWriteDbContext());#endregion EF上下文对象(主库)#region EF上下文对象(从库)protected DbContext SlaveDb => IsReadWriteSeparation ? _slaveDb.Value : _masterDb.Value;private readonly Lazy _slaveDb = new Lazy(() => new DbContextFactory().GetReadDbContext());#endregion EF上下文对象(从库)#region 自定义其他方法/// /// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)/// /// /// /// /// public List Query(string sql, List 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(sql, parms.ToArray());var enityList = list.ToList();return enityList;
        }/// /// 自定义语句和存储过程的增删改--返回影响的行数/// /// /// /// /// public int Execute(string sql, List 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 自定义其他方法}/// /// mssql数据库 数据层 父类/// /// public class DbBase : DbBase where T : class, new()
    {#region INSERT/// /// 新增 实体/// /// /// public void Insert(T model)
        {
            MasterDb.Set().Add(model);
        }/// /// 普通批量插入/// /// public void InsertRange(List datas)
        {
            MasterDb.Set().AddRange(datas);
        }#endregion INSERT#region DELETE/// /// 根据模型删除/// /// 包含要删除id的对象/// public void Delete(T model)
        {
            MasterDb.Set().Attach(model);
            MasterDb.Set().Remove(model);
        }/// /// 删除/// /// public void Delete(Expression> whereLambda)
        {
            MasterDb.Set().Where(whereLambda).Delete();
        }#endregion DELETE#region UPDATE/// /// 单个对象指定列修改/// /// 要修改的实体对象/// 要修改的 属性 名称/// /// public void Update(T model, List proNames, bool isProUpdate = true)
        {//将 对象 添加到 EF中MasterDb.Set().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 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);
                }
            }
        }/// /// 单个对象修改/// /// /// public void Update(T model)
        {
            DbEntityEntry entry = MasterDb.Entry(model);
            MasterDb.Set().Attach(model);
            entry.State = EntityState.Modified;
        }/// /// 批量修改/// /// /// public void Update(Expression> whereLambda, Expression> updateExpression)
        {
            MasterDb.Set().Where(whereLambda).Update(updateExpression);
        }/// /// 批量修改/// /// /// public void UpdateAll(List models)
        {foreach (var model in models)
            {
                DbEntityEntry entry = MasterDb.Entry(model);
                entry.State = EntityState.Modified;
            }
        }/// /// 批量统一修改/// /// 要修改的实体对象/// 查询条件/// /// public void Update(T model, Expression> whereLambda, params string[] modifiedProNames)
        {//查询要修改的数据List listModifing = MasterDb.Set().Where(whereLambda).ToList();
            Type t = typeof(T);
            List proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
            Dictionary dictPros = new Dictionary();
            proInfos.ForEach(p =>{if (modifiedProNames.Contains(p.Name))
                {
                    dictPros.Add(p.Name, p);
                }
            });if (dictPros.Count <= 0)
            {throw new Exception("指定修改的字段名称有误或为空");
            }foreach (var item in dictPros)
            {
                PropertyInfo proInfo = item.Value;//取出 要修改的值object newValue = proInfo.GetValue(model, null);//批量设置 要修改 对象的 属性foreach (T oModel in listModifing)
                {//为 要修改的对象 的 要修改的属性 设置新的值proInfo.SetValue(oModel, newValue, null);
                }
            }
        }#endregion UPDATE#region SELECT/// /// 根据主键查询/// /// /// public T FindById(dynamic id)
        {return SlaveDb.Set().Find(id);
        }/// /// 获取默认一条数据,没有则为NULL/// /// /// public T FirstOrDefault(Expression> whereLambda = null)
        {if (whereLambda == null)
            {return SlaveDb.Set().FirstOrDefault();
            }return SlaveDb.Set().FirstOrDefault(whereLambda);
        }/// /// 获取全部数据/// /// public List GetAll(string ordering = null)
        {return ordering == null? SlaveDb.Set().ToList()
                : SlaveDb.Set().OrderBy(ordering).ToList();
        }/// /// 带条件查询获取数据/// /// /// /// public List GetAll(Expression> whereLambda, string ordering = null)
        {var iQueryable = SlaveDb.Set().Where(whereLambda);return ordering == null? iQueryable.ToList()
                : iQueryable.OrderBy(ordering).ToList();
        }/// /// 带条件查询获取数据/// /// /// public IQueryable GetAllIQueryable(Expression> whereLambda = null)
        {return whereLambda == null ? SlaveDb.Set() : SlaveDb.Set().Where(whereLambda);
        }/// /// 获取数量/// /// /// public int GetCount(Expression> whereLambd = null)
        {return whereLambd == null ? SlaveDb.Set().Count() : SlaveDb.Set().Where(whereLambd).Count();
        }/// /// 判断对象是否存在/// /// /// public bool Any(Expression> whereLambd)
        {return SlaveDb.Set().Where(whereLambd).Any();
        }/// /// 分页查询/// /// 当前页码/// 每页大小/// 总条数/// 排序条件(一定要有)/// 查询添加(可有,可无)/// 是否是Order排序/// public List Page(int pageIndex, int pageSize, out int rows, Expression> orderBy, Expression> whereLambda = null, bool isOrder = true)
        {
            IQueryable data = isOrder ?SlaveDb.Set().OrderBy(orderBy) :
                SlaveDb.Set().OrderByDescending(orderBy);if (whereLambda != null)
            {
                data = data.Where(whereLambda);
            }
            rows = data.Count();return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();
        }/// /// 分页查询/// /// 当前页码/// 每页大小/// 总条数/// 排序条件(一定要有)/// 查询添加(可有,可无)/// public List Page(int pageIndex, int pageSize, out int rows, string ordering, Expression> whereLambda = null)
        {// 分页 一定注意: Skip 之前一定要 OrderByvar data = SlaveDb.Set().OrderBy(ordering);if (whereLambda != null)
            {
                data = data.Where(whereLambda);
            }
            rows = data.Count();return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();
        }/// /// 查询转换/// /// /// /// public List Select(Expression> whereLambda)
        {return SlaveDb.Set().Where(whereLambda).Select().ToList();
        }#endregion SELECT#region ORTHER/// /// 执行存储过程或自定义sql语句--返回集合/// /// /// /// /// public List Query(string sql, List parms, CommandType cmdType = CommandType.Text)
        {return Query(sql, parms, cmdType);
        }/// /// 提交保存/// /// public int SaveChanges()
        {return MasterDb.SaveChanges();
        }/// /// 回滚/// public void RollBackChanges()
        {var items = MasterDb.ChangeTracker.Entries().ToList();
            items.ForEach(o => o.State = EntityState.Unchanged);
        }#endregion ORTHER}
DbBase

  这样简单的读写分离就实现了,实现逻辑也比较清晰,方便扩展。

NexChatGPT
NexChatGPT

火爆全网的IDEA插件,支持IDEA全家桶

下载

进一步改造,实现多从库读取

  一般做读写分离,都会做一主多从,特别对读取量比较大的项目,这样多库读取就能减轻读库的压力。所以对于上面的方法,做下改造。
  上面可以看到,主库和从库都是通过 DbContextFactory 这个类来获取的,在GetReadDbContext 方法中每次都是获取 ReadDbContext 这个对象。那么对于多个从库的情况下,每次读取到底要去哪个库读取数据呢?这里就是一个算法规则的问题了,或者说是策略吧,如果使用过nginx的朋友就知道,nginx本身内部在实现负载均衡的时候提供了多种策略,比如轮询,加权轮询,ip_hash等策略。其实上面获取同一个ReadDbContext 的方法也算一种策略,叫单一策略,每次都获取单一的对象。

  多从库的情况下,我们简单的来实现另一种获取策略,随机策略,每次都随机获取到一个从库的对象,这种是最简单的策略,当然,正式使用的话大家可以发挥自己的创造力,写出多了的算法策略。

首先,定义一个策略接口,方便策略的扩展和切换,代码如下:

IReadDbStrategy 接口

 /// 
  /// 从数据库获取策略接口  /// 
  public interface IReadDbStrategy
  {      ///   /// 获取读库      ///   ///       DbContext GetDbContext();
  }

单从库情况下,定义一个单一策略,代码如下:

单一策略

   /// 
   /// 单一策略   /// 
   public class SingleStrategy : IReadDbStrategy
   {       public DbContext GetDbContext()
       {           return new ReadDbContext();
       }
   }

多从库情况下,定义一个随机策略,代码如下:

随机策略

    /// /// 随机策略/// public class RandomStrategy : IReadDbStrategy
    {//所有读库类型public static List DbTypes; static RandomStrategy()
        {
            LoadDbs();
        } //加载所有的读库类型static void LoadDbs()
        {
            DbTypes = new List();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;
        }
    }

  这样简单的一主多从也实现了。

参考文章

  
  

源码分享

  所有的代码提供给大家的更多的是一种思路和学习的参考,如果有什么不足的地方也欢迎大家批评指正,如果觉得对你有帮助,不要吝啬你的鼠标,帮忙点个星,点个赞吧。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

19

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

27

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

15

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

3

2026.02.03

漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题
漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题

本专题围绕漫蛙漫画(Manwa / Manwa2)官网网页版入口进行整理,涵盖漫蛙漫画官方主页访问方式、网页版在线阅读入口、台版正版漫画浏览说明及基础使用指引,帮助用户快速进入漫蛙漫画官网,稳定在线阅读正版漫画内容,避免误入非官方页面。

13

2026.02.03

Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口
Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口

本专题汇总了俄罗斯知名搜索引擎 Yandex 的官网入口、免登录访问地址、中文登录方法与网页版使用指南,帮助用户稳定访问 Yandex 官网,并提供一站式入口汇总。无论是登录入口还是在线搜索,用户都能快速获取最新稳定的访问链接与使用指南。

114

2026.02.03

Java 设计模式与重构实践
Java 设计模式与重构实践

本专题专注讲解 Java 中常用的设计模式,包括单例模式、工厂模式、观察者模式、策略模式等,并结合代码重构实践,帮助学习者掌握 如何运用设计模式优化代码结构,提高代码的可读性、可维护性和扩展性。通过具体示例,展示设计模式如何解决实际开发中的复杂问题。

3

2026.02.03

C# 并发与异步编程
C# 并发与异步编程

本专题系统讲解 C# 异步编程与并发控制,重点介绍 async 和 await 关键字、Task 类、线程池管理、并发数据结构、死锁与线程安全问题。通过多个实战项目,帮助学习者掌握 如何在 C# 中编写高效的异步代码,提升应用的并发性能与响应速度。

2

2026.02.03

Python 强化学习与深度Q网络(DQN)
Python 强化学习与深度Q网络(DQN)

本专题深入讲解 Python 在强化学习(Reinforcement Learning)中的应用,重点介绍 深度Q网络(DQN) 及其实现方法,涵盖 Q-learning 算法、深度学习与神经网络的结合、环境模拟与奖励机制设计、探索与利用的平衡等。通过构建一个简单的游戏AI,帮助学习者掌握 如何使用 Python 训练智能体在动态环境中作出决策。

3

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 3.9万人学习

NumPy 教程
NumPy 教程

共44课时 | 3.1万人学习

XML教程
XML教程

共142课时 | 6.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号