EFCore实现读写分离
程序员文章站
2022-06-19 11:24:52
读写分离一、数据访问层接口1.接口定义2.接口实现3.读写操作枚举类设计4.连接字符串读取设计5.DBContext拓展6.获取DBContext接口设计7.获取DBContext接口实现8.DBContext动态替换连接二、上端数据库连接字符串配置三、源码下载一、数据访问层接口1.接口定义代码如下(示例):using EFCoreDemo.CodeFirst.Migrations.Extend;using System;namespace EFCoreDemo.CodeFirst.IServ...
读写分离
一、数据访问层接口
1.接口定义
代码如下(示例):
using EFCoreDemo.CodeFirst.Migrations.Extend;
using System;
namespace EFCoreDemo.CodeFirst.IService
{
public interface IBaseService : IDisposable
{
#region Query
/// <summary>
/// 根据id查询实体
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public T Find<T>(int id, ReadWriteEnum readWriteEnum = ReadWriteEnum.Read) where T : class;
#endregion
#region Add
/// <summary>
/// 新增数据,即时Commit
/// </summary>
/// <param name="t"></param>
/// <returns>返回带主键的实体</returns>
public T Insert<T>(T t) where T : class;
#endregion
#region Delete
/// <summary>
/// 根据主键删除数据,即时Commit
/// </summary>
/// <param name="t"></param>
public void Delete<T>(int Id) where T : class;
public void Delete<T>(T t) where T : class;
#endregion
#region Other
/// <summary>
/// 立即保存全部修改
/// 把增/删的savechange给放到这里,是为了保证事务的
/// </summary>
void Commit();
#endregion
}
}
2.接口实现
代码如下(示例):
using EFCoreDemo.CodeFirst.IService;
using EFCoreDemo.CodeFirst.Migrations.Extend;
using Microsoft.EntityFrameworkCore;
using System;
namespace EFCoreDemo.CodeFirst.Service
{
public class BaseService : IBaseService, IDisposable
{
protected IDbContextFactory _ContextFactory = null;
protected DbContext _Context { get; set; }
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public BaseService(IDbContextFactory contextFactory)
{
_ContextFactory = contextFactory;
}
/// <summary>
/// 主库 即可以读取也可以增删改;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <param name="readWriteEnum"></param>
/// <returns></returns>
public T Find<T>(int id, ReadWriteEnum readWriteEnum = ReadWriteEnum.Read) where T : class
{
//ReadWriteEnum.Read;
//确定链接---从库
_Context = _ContextFactory.GetMainOrSlave(readWriteEnum);
return this._Context.Set<T>().Find(id);
}
public T Insert<T>(T t) where T : class
{
//ReadWriteEnum.Read;
//确定链接---主库
_Context = _ContextFactory.GetMainOrSlave(ReadWriteEnum.Write);
this._Context.Set<T>().Add(t);
this.Commit();//写在这里 就不需要单独commit 不写就需要
return t;
}
public void Delete<T>(int Id) where T : class
{
_Context = _ContextFactory.GetMainOrSlave(ReadWriteEnum.Write);
T t = this.Find<T>(Id);//也可以附加
if (t == null) throw new Exception("t is null");
this._Context.Set<T>().Remove(t);
this.Commit();
}
public void Delete<T>(T t) where T : class
{
_Context = _ContextFactory.GetMainOrSlave(ReadWriteEnum.Write);
if (t == null) throw new Exception("t is null");
this._Context.Set<T>().Attach(t);
this._Context.Set<T>().Remove(t);
this.Commit();
}
public void Commit()
{
this._Context.SaveChanges();
}
public void Dispose()
{
if (this._Context != null)
{
this._Context.Dispose();
}
}
}
}
3.读写操作枚举类设计
代码如下(示例):
public enum ReadWriteEnum
{
Read, //从库操作
Write //主库操作
}
4.连接字符串读取设计
代码如下(示例):
public class DBConnectionOption
{
public string MainConnectionString { get; set; }
public List<string> SlaveConnectionStringList { get; set; }
}
5.DBContext拓展
代码如下(示例):
public static class DbContextExtend
{
public static DbContext SetCurrentConnString(this DbContext dbContext, string conn)
{
if (dbContext is EFCodeFirstDemoContext)
{
var context = (EFCodeFirstDemoContext)dbContext; // context 是 EFCoreContext 实例;
return context.SetCurrentConnString(conn);
}
else
throw new Exception();
}
}
6.获取DBContext接口设计
代码如下(示例):
public interface IDbContextFactory
{
public DbContext GetMainOrSlave(ReadWriteEnum readWriteEnum);
}
7.获取DBContext接口实现
代码如下(示例):
public class DbContextFactory : IDbContextFactory
{
private DbContext _Context = null;
private DBConnectionOption _readAndWrite = null;
//private static int _iSeed = 0;//应该long
/// <summary>
///能把链接信息也注入进来
///需要IOptionsMonitor
/// </summary>
/// <param name="context"></param>
public DbContextFactory(DbContext context, IOptionsMonitor<DBConnectionOption> options)
{
_readAndWrite = options.CurrentValue;
this._Context = context;
}
public DbContext GetMainOrSlave(ReadWriteEnum readWriteEnum)
{
//判断枚举,不同的枚举可以创建不同的Context 或者更换Context链接;
switch (readWriteEnum)
{
case ReadWriteEnum.Write:
SetMainConnnectionString();
break; //选择链接//更换_Context链接 //选择链接
case ReadWriteEnum.Read:
SetSlaveConnectionString();
break; //选择链接//更换_Context链接
default:
break;
}
return _Context;
}
/// <summary>
/// 更换成主库连接
/// </summary>
/// <returns></returns>
private void SetMainConnnectionString()
{
string conn = _readAndWrite.MainConnectionString;
_Context.SetCurrentConnString(conn);
}
private static int _iSeed = 0;
/// <summary>
/// 更换成主库连接
///
/// ///策略---数据库查询的负载均衡
/// </summary>
/// <returns></returns>
private void SetSlaveConnectionString()
{
string conn = string.Empty;
{
// //随机
//int Count= _readAndWrite.ReadConnectionList.Count;
//int index= new Random().Next(0, Count);
//conn = _readAndWrite.ReadConnectionList[index];
}
{
//来一个轮询
conn = this._readAndWrite.SlaveConnectionStringList[_iSeed++ % this._readAndWrite.SlaveConnectionStringList.Count];//轮询;
}
{
///是不是可以直接配置到配置文件里面
}
_Context.SetCurrentConnString(conn);
}
}
8.DBContext动态替换连接
代码如下(示例):
private string CurrentConnString = null;
public DbContext SetCurrentConnString(string conn)
{
CurrentConnString = conn;
return this;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseLazyLoadingProxies()
.UseSqlServer(CurrentConnString);
//.UseSqlServer("Server=.;Database=EFCoreCodeFirstDemo;uid=sa;pwd=Lykj20190325");
}
optionsBuilder.UseLoggerFactory(MyLoggerFactory);
}
二、上端数据库连接字符串配置
在appsettings.json文件中加入ConnectionStrings节点
代码如下(示例):
"ConnectionStrings": {
"MainConnectionString": "Server=.;Database=EFCoreCodeFirstDemo;uid=sa;pwd=Lykj20190325",
"SlaveConnectionStringList": [
"Server=.;Database=SlaveEFCoreCodeFirstDemo01;uid=sa;pwd=Lykj20190325",
"Server=.;Database=SlaveEFCoreCodeFirstDemo02;uid=sa;pwd=Lykj20190325",
"Server=.;Database=SlaveEFCoreCodeFirstDemo03;uid=sa;pwd=Lykj20190325"
]
}
三、源码下载
本文地址:https://blog.csdn.net/fisea/article/details/111982136