业务需要 配置一主多从数据库 读写分离  orm用的ef core , 把思路和代码写下

1. 配置2个数据库上下文 ETMasterContext  ETSlaveContext(把增删改功能禁用掉)

public class ETMasterContext : DbContext
     {
         public ETMasterContext(DbContextOptions<ETMasterContext> options)
             : base(options)
         {

}

public DbSet<User> Users { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
         {
             base.OnModelCreating(modelBuilder);

modelBuilder.ApplyConfiguration(new UserConfiguration());
         }
     }

public class ETSlaveContext : DbContext
     {
         public ETSlaveContext(DbContextOptions<ETSlaveContext> options)
             : base(options)
         {

}

public DbSet<User> Users { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
         {
             base.OnModelCreating(modelBuilder);

modelBuilder.ApplyConfiguration(new UserConfiguration());

}
         public override int SaveChanges()
         {
             throw new InvalidOperationException("只读数据库,不允许写入");
         }
         public override int SaveChanges(bool acceptAllChangesOnSuccess)
         {
             throw new InvalidOperationException("只读数据库,不允许写入");
         }
         public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
         {
             throw new InvalidOperationException("只读数据库,不允许写入");
         }
         public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
         {
             throw new InvalidOperationException("只读数据库,不允许写入");
         }

}

2. 定义2个Repository  EfRepository(主)    EfReadOnlyRepository(只读)

public class EfRepository<T> : IRepository<T> where T : EntityBase
     {
         protected readonly ETMasterContext Context;

public EfRepository(ETMasterContext context)
         {
             Context = context;
             //Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
         }

public IQueryable<T> Table => Context.Set<T>().AsQueryable();

public IQueryable<T> TableNoTracking => Context.Set<T>().AsNoTracking();

public int Delete(T entity)
         {
             try
             {
                 Context.Set<T>().Remove(entity);
                 return 1;
             }
             catch (Exception)
             {

return 0;
             }
         }

public int DeleteWhere(Expression<Func<T, bool>> criteria)
         {
             try
             {
                 IQueryable<T> entities = Context.Set<T>().Where(criteria);
                 foreach (var entity in entities)
                 {
                     Context.Entry(entity).State = EntityState.Deleted;
                 }
                 return 1;
             }
             catch (Exception)
             {
                 return 0;
             }

}

public T GetById(object id)
         {
             return Context.Set<T>().Find(id);
         }

public int Insert(T entity)
         {
             try
             {
                 Context.Set<T>().Add(entity);
                 return 1;
             }
             catch (Exception ex)
             {
                 return 0;
             }

}

public int InsertMany(IEnumerable<T> list)
         {
             try
             {
                 Context.Set<T>().AddRange(list);
                 return 1;
             }
             catch (Exception ex)
             {
                 return 0;
             }
         }

public int Update(T entity)
         {
             try
             {
                 Context.Entry(entity).State = EntityState.Modified;
                 return 1;
             }
             catch (Exception)
             {
                 return 0;
             }
         }
     }

public class EfReadOnlyRepository<T> : IReadOnlyRepository<T> where T : EntityBase
     {
         protected readonly ETSlaveContext Context;

public EfReadOnlyRepository(ETSlaveContext context)
         {
             Context = context;
             //Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
         }

public IQueryable<T> Table => Context.Set<T>().AsQueryable();

public IQueryable<T> TableNoTracking => Context.Set<T>().AsNoTracking();

public T GetById(object id)
         {
             return Context.Set<T>().Find(id);
         }
     }

3. 用到的接口补上

public interface IReadOnlyRepository<T> where T : EntityBase

{
     IQueryable<T> Table { get; }

IQueryable<T> TableNoTracking { get; }
     T GetById(object id);

}

public interface IRepository<T> : IReadOnlyRepository<T> where T : EntityBase

{
     int Insert(T entity);
     int InsertMany(IEnumerable<T> list);
     int Update(T entity);
     int Delete(T entity);
     int DeleteWhere(Expression<Func<T, bool>> criteria);

}

4. Startup  ConfigureServices 中配置上下文

services.AddDbContext<ETMasterContext>(options =>
     options.UseMySql(GetConnectionStringByRandom("MySql_Master")));

services.AddDbContext<ETSlaveContext>(options =>
     options.UseMySql(GetConnectionStringByRandom("MySql_Slave")));

private string GetConnectionStringByRandom(string connectionString)

{
     var connstr = Configuration.GetConnectionString(connectionString);
     if (string.IsNullOrEmpty(connstr))
     {
         throw new Exception("数据库配置有误");
     }

var conList = connstr.Trim('|').Split('|');
     var rand = new Random().Next(0, conList.Length);
     return conList[rand];

}

5. appsetting.json 配置多个连接字符串  | 分隔

"connectionStrings": {
   "MySql_Master": "server=192.168.87.169;database=poker_games;uid=root;pwd=1$=6yuan;SslMode=None;",
   "MySql_Slave": "server=192.168.87.169;database=poker_games;uid=root;pwd=1$=6yuan;SslMode=None;|server=192.168.87.169;database=poker_games;uid=root;pwd=1$=6yuan;SslMode=None;"

}

6. 实际应用

public class ReportService : IReportService
     {
         private readonly IHttpContextAccessor _httpContextAccessor;
         private readonly IDistributedCache _distributedCache;
         private readonly IUnitOfWork _unitOfWork;
         private readonly IMapper _mapper;
         private readonly IReadOnlyRepository<Bet> _betRepository;

public ReportService(
             IHttpContextAccessor httpContextAccessor,
             IDistributedCache distributedCache,
             IUnitOfWork unitOfWork,
             IMapper mapper,
             IReadOnlyRepository<Bet> betRepository
             )
         {
             _httpContextAccessor = httpContextAccessor;
             _distributedCache = distributedCache;
             _unitOfWork = unitOfWork;
             _mapper = mapper;
             _betRepository = betRepository;
         }

}

public ReturnValue GetAgentBetReportByRound(AgentBetReportByRoundCriteriaModel reportModel)
         {

var betList = _betRepository.TableNoTracking.Where(p => p.pay_out_date >= beginTime && p.pay_out_date < endTime);
            
             return new ReturnValue(betList );

}

7. 大概解释下

如图 DBContext的生命周期默认是Scoped,即整个reqeust请求的生命周期以内共用了一个Context

利用这个生命周期 在每次请求时 通过配置文件获取不同的上下文实例 即实现了 多主多从 读写分离功能

EF Ccore 主从配置 最简化的更多相关文章

  1. mongodb3.x主从配置及备份

    本文将介绍下mongodb主从配置及备份 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关 ...

  2. docker Redis的主从配置

    redis是k-v型nosql数据库,支持字符串(string).列表(list).集合(set).散列(hash).有序集合(zset:形如member:score的散列集合,其中member为成员 ...

  3. CentO7 安装 redis, 主从配置,Sentinel集群故障转移切换

        一.Redis的安装(前提是已经安装了EPEL)   安装redis: yum -y install redis 启动/停止/重启 Redis 启动服务: systemctl start re ...

  4. PostgreSQL9.6主从配置

    参考文档: 备机日志传送:https://www.postgresql.org/docs/9.6/static/warm-standby.html 英文文档:https://www.postgresq ...

  5. MySQL主从配置详解

    一.mysql主从原理 1. 基本介绍 MySQL 内建的复制功能是构建大型,高性能应用程序的基础.将 MySQL 的 数亿分布到到多个系统上去,这种分步的机制,是通过将 MySQL 的某一台主机的数 ...

  6. Redis学习总结(四)--Redis主从配置

    在分布式系统架构设计中高可用是必须考虑的因素之一.高可用通常是指,通过设计减少系统不能提供服务的时间.而单点是系统高可用的最大的败笔,如果单点出现问题的话,那么整个服务就不能使用了,所以应该尽量在系统 ...

  7. mysql主从配置实现一主一从读写分离

    主从介绍Mysql主从又叫Replication.AB复制.简单讲就是A与B两台机器做主从后,在A上写数据,另外一台B也会跟着写数据,实现数据实时同步mysql主从是基于binlog,主上需开启bin ...

  8. mysql主从配置

    引言: 双11,阿里云服务器打折,于是我忍不住又买了一台服务器,于是咱也是有两台服务器的爷们了,既然有了两台服务器,那么肯定要好好利用一下吧,那么就来玩玩mysql的主从配置吧. 准备 两台数据库服务 ...

  9. postgresql pgsql最新版安装指南及数据存储路径更改及主从配置

    postgresql pgsql最新版安装指南及数据存储路径更改及主从配置 安装指南 首先在apt的list添加你当前系统版本对应的apt列表 目前官网有16.04,14.04,12.04 分别对应下 ...

随机推荐

  1. vue之mapMutaions的使用 && vuex中 action 用法示例 && api.js的使用

    vue之mapMutations的使用 我们通过Mutation来改变store中的state,方法往往是在子组件中使用 this.$store.commit(); 来实现,但是这样的缺点是不容易查看 ...

  2. 阿冰教你一步一步做Android新闻客户端(二)两种异步线程加载图片的方法

    哈哈哈抱着没人看的心态随便写,直接上代码,各位看官看注释 一种Thread  一种AsyncTask 先不说用框架 public class ImageLoader { private ImageVi ...

  3. xlua的自定义加载

    具体可以先看xlua的自定义加载的demo,那个用lamda表达式做的 我这个更好理解 主要是ReadFile2的结构问题,必须的写成这样

  4. VS2010中VC++目录和C/C++之间的区别。VC++ Directories和C/C++的区别。

    首先,这是个历史遗留问题,说起来比较复杂.其次,这个问题在微软的MSDN博客上已经专门被说起过了,英文好的请直接移步到原文:<VC++ Directories>.另外,stack over ...

  5. java中HashMap的keySet()和values()

    我们通常说,keySet()返回所有的键,values()返回所有的值,其实是不太对的,因为无论是keySet()和values(),其实都没有实质的内容,且容我慢慢说来. 他们前者返回了一个Set, ...

  6. 自己实现C++的string类

    使用C++的朋友对string类都不会陌生,string类使用起来很是方便,比C的字符数组好用多了,但是我们能不能自己实现一个属于自己的string类呢? 实现一个具有基本功能的string类并不难, ...

  7. newInstance和new的区别(good)

    从JVM 的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载.但是使用newInstance()方法的时候,就必须保证:1.这个 类已经加载:2.这个类已经连接了.而完成上面两个步骤 ...

  8. C#语言-02.数据类型

    a. 数据类型 i. 值类型:是一种由类型的实际值表示的数据类型,存储在栈内的存储空间中,由于编译器编译后将源代码中的值类型变量直接对应到唯一的存储空间上,直接访问该存储空间,故值类型的数据具有较快地 ...

  9. select支持多查询,获取分页count

    在我们使用mybatis 时,当我们根据分页去查询数据集时,需要传入的参数有page(页码)和size(每页的条数),而我们期望获取到的数据有,小于或等于size的list数据集,同时我们还需要得到一 ...

  10. python的传递实参

    你经常会发现,向函数传递列表很有用,这种列表包含的可能是名字.数字或更复杂的对象(如字典).将列表传递给函数后,函数就能直接访问其内容 1.在函数中修改列表 将列表传递给函数后,函数就可对其进行修改. ...