设为首页 加入收藏

TOP

EF Core 实现读写分离的最佳方案(一)
2019-10-09 19:59:10 】 浏览:145
Tags:Core 实现 读写 分离 最佳 方案

前言

公司之前使用Ado.net和Dapper进行数据访问层的操作, 进行读写分离也比较简单, 只要使用对应的数据库连接字符串即可. 而最近要迁移到新系统中,新系统使用.net core和EF Core进行数据访问. 所以趁着国庆假期拿出一两天时间研究了一下如何EF Core进行读写分离.

思路

根据园子里的Jeffcky大神的博客, 参考
EntityFramework Core进行读写分离最佳实践方式,了解一下(一)?
EntityFramework Core进行读写分离最佳实践方式,了解一下(二)?

最简单的思路就是使用手动切换EF Core上下文的连接, 即context.Database.GetDbConnection().ConnectionString = "xxx", 但必须要先创建上下文, 再关闭之前的连接, 才能进行切换
另一种方式是通过监听Diagnostic来将进行查询的sql切换到从库执行, 这种方式虽然可以实现无感知的切换操作, 但不能满足公司的业务需求. 在后台管理或其他对数据实时性要求比较高的项目里,查询操作也都应该走主库,而这种方式却会切换到从库去. 另一方面就是假若公司的库比较多,每种业务都对应了一个库, 每个库都对应了一种DbContext, 这种情况下, 要实现自动切换就变得很复杂了.

上面的两种方式都是从切换数据库连接入手,但是频繁的切换数据库连接势必会对性能造成影响. 我认为最理想的方式是要避免数据库连接的切换, 且能够适应多DbContext的情况, 在创建上下文实例时,就指定好是访问主库还是从库, 而不是在后期再进行数据库切换. 因此, 在上下文实例化时,就传入相应的数据库连接字符串, 这样一来DbContext的创建就需要交由我们自己来进行, 就不是由DI容器进行创建了. 同时仓储应该区分为只读和可读可写两种,以防止其他人对从库进行写操作.

实现

    public interface IReadOnlyRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>
        where TKey : IEquatable<TKey>
    {}

    public interface IRepository<TEntity, TKey> : IReadOnlyRepository<TEntity, TKey>
    where TEntity : class, IEntity<TKey>
    where TKey : IEquatable<TKey>
    {}

IReadOnlyRepository接口是只读仓储接口,提供查询相关方法,IRepository接口是可读可写仓储接口,提供增删查改等方法, 接口的实现就那些东西这里就省略了.

    public interface IRepositoryFactory
    {
        IRepository<TEntity, TKey> GetRepository<TEntity, TKey>(IUnitOfWork unitOfWork)
            where TEntity : class, IEntity<TKey>
            where TKey : IEquatable<TKey>;
         IReadOnlyRepository<TEntity, TKey> GetReadOnlyRepository<TEntity, TKey>(IUnitOfWork unitOfWork)
                where TEntity : class, IEntity<TKey>
                where TKey : IEquatable<TKey>;
    }
    public class RepositoryFactory : IRepositoryFactory
    {
        public RepositoryFactory()
        {
        }

        public IRepository<TEntity, TKey> GetRepository<TEntity, TKey>(IUnitOfWork unitOfWork)
            where TEntity : class, IEntity<TKey>
            where TKey : IEquatable<TKey>
        {
            return new Repository<TEntity, TKey>(unitOfWork);
        }

        public IReadOnlyRepository<TEntity, TKey> GetReadOnlyRepository<TEntity, TKey>(IUnitOfWork unitOfWork)
            where TEntity : class, IEntity<TKey>
            where TKey : IEquatable<TKey>
        {
            return new ReadOnlyRepository<TEntity, TKey>(unitOfWork);
        }
    }

RepositoryFactory提供仓储对象的实例化

    public interface IUnitOfWork : IDisposable
    {
        public DbContext DbContext { get; }

        /// <summary>
        /// 获取只读仓储对象
        /// </summary>
        IReadOnlyRepository<TEntity, TKey> GetReadOnlyRepository<TEntity, TKey>()
            where TEntity : class, IEntity<TKey>
            where TKey : IEquatable<TKey>;

        /// <summary>
        /// 获取仓储对象
        /// </summary>
        IRepository<TEntity, TKey> GetRepository<TEntity, TKey>()
            where TEntity : class, IEntity<TKey>
            where TKey : IEquatable<TKey>;
        int SaveChanges();
        Task<int> SaveChangesAsync(CancellationToken cancelToken = default);
    }
    
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly DbContext _dbContext;
        private readonly IRepositoryFactory _repositoryFactory;
        private bool _disposed;

        public UnitOfWork(IServiceProvider serviceProvider, DbContext context)
        {
            Check.NotNull(serviceProvider, nameof(serviceP
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇矩阵连乘求解优化 下一篇在 ASP.NET Core 项目中使用 Auto..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目