search
HomeBackend DevelopmentC#.Net TutorialSummary of EF general data layer encapsulation class examples detailed explanation
Summary of EF general data layer encapsulation class examples detailed explanationJun 24, 2017 am 09:54 AM
encapsulationsupportdataRead and writeUniversal

Brief Talk about ORM

I remember the first time I came into contact with Ling to Sql in school four years ago. At that time, I instantly realized how convenient it was to not write SQL statements by hand. Later, I gradually came into contact with many ORM frameworks. Like EF, Dapper, Hibernate, ServiceStack.OrmLite , etc. Of course, each ORM has its own advantages and disadvantages. There are also many masters in the garden who have open sourced the ORM they wrote, such as SqlSugar, Chloe.ORM, CYQ.Data wait. Let’s not talk about the usage of these open source ORMs. I think they are commendable at least in terms of the spirit of open source. I have also downloaded the source code of these great masters to study.
The ultimate point of all ORM is convenience, which reduces repetitive work for programmers. Of course, some companies still use handwritten SQL to do it. I think it is a bit idle to use handwritten SQL for the entire project. It hurts. It’s not that I don’t recommend handwriting SQL, but I personally think that if the most basic additions, deletions, modifications and queries are written by hand, the test is not ability, but endurance. Some people say that the handwritten SQL method has strong controllability and high performance. What I want to say is that ORM can also do it. The key is how you use it.
The advantages of ORM are very obvious, and development is convenient, but perhaps it is also because of this advantage that many lazy programmers will gradually forget how to write SQL statements. I have met many programmer friends who use EF and write by hand. I no longer want to use sql, views, and stored procedures. I personally feel that handwritten sql is still necessary. Otherwise, one day when you see "exec xxxx" written in someone else's program, you will suddenly think, "Ah, I seem to have seen it somewhere...". So what I want to say is "You still have to take action when it's time to take action."

A brief talk about Entity Framework

Entity Framework is Microsoft’s ORM framework. With the continuous improvement and strengthening of Entity Framework, I believe that the proportion of usage is still higher compared to other ORMs. The ones I currently use the most are EF and Dapper. Indeed, it will be much more convenient to use EF during the development process. After all, EF has gone through so many years, both in terms of maturity and performance, etc. have improved a lot. There are also many developers who have provided extended functions for EF, such as entity framework extended etc. Moreover, as a .net developer, the project is very versatile, there is a lot of information, and Microsoft’s updates in this area are also very powerful. However, the EF Core that was just released also has some pitfalls. After all, it is still in its early stages. I believe it will get better and better in the future.

Entity Framework provides three development modes, code first, db first, and model first. The most commonly used one at present is code first. As for the simple use and differences of these three modes, you can refer to this article.

I have heard some friends say that the performance of EF is poor and the generated SQL statements are ugly. I think you should check the code or read more EF articles before saying this. You should first make sure that you are not digging a hole for yourself before you can accuse others of their faults. If you really feel that EF or other ORMs are uncomfortable to use, then write one yourself. I once used Dapper with my colleagues to extend a general ORM, which was out of the convenience of learning and use.

Entity Framework Universal Data Layer Class

The EF universal data layer parent class method is provided here. In fact, many people on the Internet have provided the EF universal data layer parent class method in their own projects, so here What is provided is not the optimal and best choice. It can only be said to be a universal class for everyone to learn and use. The specific code is as follows:

DbContextFactory DbContext Factory Class

    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 data layer general operation class

 public class DbBase
    {protected DbContext Db = new DbContextFactory().GetDbContext();        #region 自定义其他方法/// <summary>/// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)/// </summary>/// <param>/// <param>/// <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>/// <param>/// <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></typeparam>public class DbBase<t> : DbBase where T : class, new()
    {#region INSERT/// <summary>/// 新增 实体/// </summary>/// <param>/// <returns></returns>public void Insert(T model)
        {
            Db.Set<t>().Add(model);

        }/// <summary>/// 普通批量插入/// </summary>/// <param>public void InsertRange(List<t> datas)
        {
            Db.Set<t>().AddRange(datas);
        }#endregion INSERT#region DELETE/// <summary>/// 根据模型删除/// </summary>/// <param>包含要删除id的对象/// <returns></returns>public void Delete(T model)
        {
            Db.Set<t>().Attach(model);
            Db.Set<t>().Remove(model);
        }/// <summary>/// 删除/// </summary>/// <param>public void Delete(Expression<func>> whereLambda)
        {
            Db.Set<t>().Where(whereLambda).Delete();
        }#endregion DELETE#region UPDATE/// <summary>/// 单个对象指定列修改/// </summary>/// <param>要修改的实体对象/// <param>要修改的 属性 名称/// <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>/// <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>/// <param>public void Update(Expression<func>> whereLambda, Expression<func>> updateExpression)
        {
            Db.Set<t>().Where(whereLambda).Update(updateExpression);
        }/// <summary>/// 批量修改/// </summary>/// <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>要修改的实体对象/// <param>查询条件/// <param>/// <returns></returns>public void Update(T model, Expression<func>> 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> dictPros = new Dictionary<string>();
            proInfos.ForEach(p =>{if (modifiedProNames.Contains(p.Name))
                {
                    dictPros.Add(p.Name, p);
                }
            });if (dictPros.Count /// 根据主键查询/// /// <param>/// <returns></returns>public T FindById(dynamic id)
        {return Db.Set<t>().Find(id);
        }/// <summary>/// 获取默认一条数据,没有则为NULL/// </summary>/// <param>/// <returns></returns>public T FirstOrDefault(Expression<func>> 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>/// <param>/// <returns></returns>public List<t> GetAll(Expression<func>> whereLambda, string ordering = null)
        {var iQueryable = Db.Set<t>().Where(whereLambda);return ordering == null? iQueryable.ToList()
                : iQueryable.OrderBy(ordering).ToList();
        }/// <summary>/// 带条件查询获取数据/// </summary>/// <param>/// <returns></returns>public IQueryable<t> GetAllIQueryable(Expression<func>> whereLambda = null)
        {return whereLambda == null ? Db.Set<t>() : Db.Set<t>().Where(whereLambda);
        }/// <summary>/// 获取数量/// </summary>/// <param>/// <returns></returns>public int GetCount(Expression<func>> whereLambd = null)
        {return whereLambd == null ? Db.Set<t>().Count() : Db.Set<t>().Where(whereLambd).Count();
        }/// <summary>/// 判断对象是否存在/// </summary>/// <param>/// <returns></returns>public bool Any(Expression<func>> whereLambd)
        {return Db.Set<t>().Where(whereLambd).Any();
        }/// <summary>/// 分页查询/// </summary>/// <param>当前页码/// <param>每页大小/// <param>总条数/// <param>排序条件(一定要有)/// <param>查询添加(可有,可无)/// <param>是否是Order排序/// <returns></returns>public List<t> Page<tkey>(int pageIndex, int pageSize, out int rows, Expression<func>> orderBy, Expression<func>> 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>当前页码/// <param>每页大小/// <param>总条数/// <param>排序条件(一定要有)/// <param>查询添加(可有,可无)/// <returns></returns>public List<t> Page(int pageIndex, int pageSize, out int rows, string ordering, Expression<func>> 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></typeparam>/// <param>/// <returns></returns>public List<tdto> Select<tdto>(Expression<func>> whereLambda)
        {return Db.Set<t>().Where(whereLambda).Select<tdto>().ToList();
        }#endregion SELECT#region ORTHER/// <summary>/// 执行存储过程或自定义sql语句--返回集合/// </summary>/// <param>/// <param>/// <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}</t></sqlparameter></t></tdto></t></func></tdto></tdto></t></func></t></t></t></t></func></func></tkey></t></t></func></t></t></func></t></t></func></t></t></func></t></t></t></t></t></t></func></t></string></string></propertyinfo></t></t></func></t></t></func></func></t></t></propertyinfo></t></string></t></func></t></t></t></t></t></t></sqlparameter></tmodel></sqlparameter></tmodel></tmodel>
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<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>/// <param>/// <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>/// <param>/// <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></typeparam>public class DbBase<t> : DbBase where T : class, new()
    {#region INSERT/// <summary>/// 新增 实体/// </summary>/// <param>/// <returns></returns>public void Insert(T model)
        {
            MasterDb.Set<t>().Add(model);
        }/// <summary>/// 普通批量插入/// </summary>/// <param>public void InsertRange(List<t> datas)
        {
            MasterDb.Set<t>().AddRange(datas);
        }#endregion INSERT#region DELETE/// <summary>/// 根据模型删除/// </summary>/// <param>包含要删除id的对象/// <returns></returns>public void Delete(T model)
        {
            MasterDb.Set<t>().Attach(model);
            MasterDb.Set<t>().Remove(model);
        }/// <summary>/// 删除/// </summary>/// <param>public void Delete(Expression<func>> whereLambda)
        {
            MasterDb.Set<t>().Where(whereLambda).Delete();
        }#endregion DELETE#region UPDATE/// <summary>/// 单个对象指定列修改/// </summary>/// <param>要修改的实体对象/// <param>要修改的 属性 名称/// <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>/// <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>/// <param>public void Update(Expression<func>> whereLambda, Expression<func>> updateExpression)
        {
            MasterDb.Set<t>().Where(whereLambda).Update(updateExpression);
        }/// <summary>/// 批量修改/// </summary>/// <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>要修改的实体对象/// <param>查询条件/// <param>/// <returns></returns>public void Update(T model, Expression<func>> 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> dictPros = new Dictionary<string>();
            proInfos.ForEach(p =>{if (modifiedProNames.Contains(p.Name))
                {
                    dictPros.Add(p.Name, p);
                }
            });if (dictPros.Count /// 根据主键查询/// /// <param>/// <returns></returns>public T FindById(dynamic id)
        {return SlaveDb.Set<t>().Find(id);
        }/// <summary>/// 获取默认一条数据,没有则为NULL/// </summary>/// <param>/// <returns></returns>public T FirstOrDefault(Expression<func>> 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>/// <param>/// <returns></returns>public List<t> GetAll(Expression<func>> whereLambda, string ordering = null)
        {var iQueryable = SlaveDb.Set<t>().Where(whereLambda);return ordering == null? iQueryable.ToList()
                : iQueryable.OrderBy(ordering).ToList();
        }/// <summary>/// 带条件查询获取数据/// </summary>/// <param>/// <returns></returns>public IQueryable<t> GetAllIQueryable(Expression<func>> whereLambda = null)
        {return whereLambda == null ? SlaveDb.Set<t>() : SlaveDb.Set<t>().Where(whereLambda);
        }/// <summary>/// 获取数量/// </summary>/// <param>/// <returns></returns>public int GetCount(Expression<func>> whereLambd = null)
        {return whereLambd == null ? SlaveDb.Set<t>().Count() : SlaveDb.Set<t>().Where(whereLambd).Count();
        }/// <summary>/// 判断对象是否存在/// </summary>/// <param>/// <returns></returns>public bool Any(Expression<func>> whereLambd)
        {return SlaveDb.Set<t>().Where(whereLambd).Any();
        }/// <summary>/// 分页查询/// </summary>/// <param>当前页码/// <param>每页大小/// <param>总条数/// <param>排序条件(一定要有)/// <param>查询添加(可有,可无)/// <param>是否是Order排序/// <returns></returns>public List<t> Page<tkey>(int pageIndex, int pageSize, out int rows, Expression<func>> orderBy, Expression<func>> 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>当前页码/// <param>每页大小/// <param>总条数/// <param>排序条件(一定要有)/// <param>查询添加(可有,可无)/// <returns></returns>public List<t> Page(int pageIndex, int pageSize, out int rows, string ordering, Expression<func>> 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></typeparam>/// <param>/// <returns></returns>public List<tdto> Select<tdto>(Expression<func>> whereLambda)
        {return SlaveDb.Set<t>().Where(whereLambda).Select<tdto>().ToList();
        }#endregion SELECT#region ORTHER/// <summary>/// 执行存储过程或自定义sql语句--返回集合/// </summary>/// <param>/// <param>/// <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}</t></sqlparameter></t></tdto></t></func></tdto></tdto></t></func></t></t></t></t></func></func></tkey></t></t></func></t></t></func></t></t></func></t></t></func></t></t></t></t></t></t></func></t></string></string></propertyinfo></t></t></func></t></t></func></func></t></t></propertyinfo></t></string></t></func></t></t></t></t></t></t></sqlparameter></tmodel></sqlparameter></tmodel></tmodel></dbcontext></dbcontext></dbcontext></dbcontext>
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;
        }
    }</type></type>

  这样,所有从库我们都基于策略去获取,扩展也比较方便。修改下 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;
        }
    }

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

参考文章

  
  

源码分享

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

The above is the detailed content of Summary of EF general data layer encapsulation class examples detailed explanation. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
如何解决Windows Hello不支持的摄像头问题如何解决Windows Hello不支持的摄像头问题Jan 05, 2024 pm 05:38 PM

使用windowshello中,找不到支持的摄像头,常见的原因是使用的摄像头不支持人脸识别、摄像头驱动安装不正确导致的,那么接下来让我们一起去看一下怎么去设置。windowshello找不到支持的摄像头教程:原因一:摄像头驱动安装不对1、一般来说Win10系统可以自动为大部分摄像头安装驱动程序,如下,插上摄像头之后会有通知;2、这时我们打开设备管理器看看,摄像头驱动是否安装好,没有的话就需要手动操作一下。WIN+X,然后选择设备管理器;3、设备管理器窗口中,展开照相机选项,会显示摄像头的驱动型号

PyCharm社区版支持的插件足够吗?PyCharm社区版支持的插件足够吗?Feb 20, 2024 pm 04:42 PM

PyCharm社区版支持的插件足够吗?需要具体代码示例随着Python语言在软件开发领域的应用越来越广泛,PyCharm作为一款专业的Python集成开发环境(IDE),备受开发者青睐。PyCharm分为专业版和社区版两个版本,其中社区版是免费提供的,但其插件支持相对专业版有所限制。那么问题来了,PyCharm社区版支持的插件足够吗?本文将通过具体的代码示例

优缺点分析:深入了解开源软件的利弊优缺点分析:深入了解开源软件的利弊Feb 23, 2024 pm 11:00 PM

开源软件的利与弊:了解开源项目的优劣势,需要具体代码示例在当今数字化时代,开源软件越来越受到关注和推崇。作为一种基于合作和分享精神的软件开发模式,开源软件在不同领域都有着广泛的应用。然而,尽管开源软件具有诸多优势,但也存在一些挑战和限制。本文将深入探讨开源软件的利与弊,并通过具体的代码示例展示开源项目的优劣势。一、开源软件的优势1.1开放性和透明性开源软件

华硕TUF Z790 Plus兼容华硕MCP79内存的频率华硕TUF Z790 Plus兼容华硕MCP79内存的频率Jan 03, 2024 pm 04:18 PM

华硕tufz790plus支持内存频率华硕TUFZ790-PLUS主板是一款高性能主板,支持双通道DDR4内存,最大支持64GB内存。它的内存频率非常强大,最高可达4800MHz。具体支持的内存频率包括2133MHz、2400MHz、2666MHz、2800MHz、3000MHz、3200MHz、3600MHz、3733MHz、3866MHz、4000MHz、4133MHz、4266MHz、4400MHz、4533MHz、4600MHz、4733MHz和4800MHz。无论是日常使用还是高性能需

GTX960与XP系统的兼容性及相关说明GTX960与XP系统的兼容性及相关说明Dec 28, 2023 pm 10:22 PM

有一些用户使用xp系统,想要将他们的显卡升级为gtx960,但不确定gtx960是否支持xp系统。实际上,gtx960是支持xp系统的。我们只需在官网下载适用于xp系统的驱动程序,就可以使用gtx960了。下面让我们一起来看看具体的步骤吧。gtx960支持xp系统吗:GTX960可以与XP系统兼容。只需要下载并安装驱动程序,你就可以开始使用了。首先,我们需要打开NVIDIA官网并导航到主页。然后,我们需要在页面上方找到一个标签或按钮,它可能会被标记为“驱动程序”。一旦找到了这个选项,我们需要点击

如何使用Flask-Babel实现多语言支持如何使用Flask-Babel实现多语言支持Aug 02, 2023 am 08:55 AM

如何使用Flask-Babel实现多语言支持引言:随着互联网的不断发展,多语言支持成为了大多数网站和应用的一个必要功能。Flask-Babel是一个方便易用的Flask扩展,它提供了基于Babel库的多语言支持。本文将介绍如何使用Flask-Babel来实现多语言支持,并附上代码示例。一、安装Flask-Babel在开始之前,我们需要先安装Flask-Bab

ios18支持哪几款机型ios18支持哪几款机型Jan 07, 2024 pm 01:21 PM

有可靠内部渠道传来的神秘消息,告诉人们iOS18将会带来一系列颠覆想象的重大更新,甚至计划推出震撼大众的潜在生成式人工智能!那么它支持的机型都有哪些呢?ios18支持哪几款机型答:ios18可能支持iPhone11及以上的机型。针对备受关注却仍旧保密甚严的iOS18系统,虽然目前披露的相关细节甚少,但根据传言指出,苹果正在投入大量资源研究人工智能服务与功能,并且预计最早将会在2024年底才能和大家见面。据相关消息称,苹果正在该领域内部自主研发AppleGPT,以对话式、图像生成、多模型为主打,是

启用安全启动是升级win11的必要条件吗?如何打开安全启动功能启用安全启动是升级win11的必要条件吗?如何打开安全启动功能Jan 29, 2024 pm 08:33 PM

大家都知道,要安装win11系统,需要确保电脑支持TPM2.0并开启安全启动。如果你的电脑安装win11失败,可能是因为安全启动未开启。以下是一些品牌电脑开启安全启动的教程,希望对你有所帮助。升级win11提示必须支持安全启动怎么办?一、华硕主板1、首先我们切换中文,然后根据提示按键盘的F7打开高级设置。3、然后选择其中的密钥管理。二、联想电脑1、2020年前的联想电脑型号,需要使用F2进入bios设置,然后在上方选中security。2、在security选项卡下降secureboot更改为E

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!