首页 文章

CQRS的EF读写模式

提问于
浏览
0

我已经读过Dapper比EF一般要快得多,并且正在考虑使用Dapper作为查询端,EF考虑使用CQRS(lite)模式的应用程序写入端 .

但是,我也知道EF可以默认关闭跟踪功能 . 是否值得创建2个数据库上下文,一个用于在所有实体中启用AsNoTracking进行阅读,另一个用于在启用跟踪的情况下进行写入?这样,我可以在不使用其他库的情况下获得性能优势并增加额外的复杂性

1 回答

  • 2

    对于Entity Framework,您的应用程序中只应有一个 DbContext .

    您可以考虑使用上下文的简单抽象来为您提供读取端和写入端:

    public abstract class Entity
    {
        // Marker class
    }
    
    public interface IEntityReader<out TEntity> where TEntity : Entity
    {
        IQueryable<TEntity> Query();
    }
    
    public interface IEntityWriter<TEntity> where TEntity : Entity
    {
        TEntity Get(object primaryKey);
    
        void Save(TEntity entity);
    
        void Delete(TEntity entity);
    }
    

    这些实现如下:

    internal sealed class EntityFrameworkReader<TEntity> : IEntityReader<TEntity> where TEntity : Entity
    {
        private readonly Func<DbContext> _contextProvider;
    
        public EntityFrameworkReader(Func<DbContext> contextProvider)
        {
            _contextProvider = contextProvider;
        }
    
        public IQueryable<TEntity> Query()
        {
            return _contextProvider().Set<TEntity>().AsNoTracking();
        }
    
    }
    
    internal sealed class EntityFrameworkWriter<TEntity> : IEntityWriter<TEntity> where TEntity : Entity
    {
        private readonly Func<DbContext> _contextProvider;
    
        public EntityFrameworkWriter(Func<DbContext> contextProvider)
        {
            _contextProvider = contextProvider;
        }
    
        public void Save(TEntity entity)
        {
            var context = _contextProvider();
            var entry = context.Entry(entity);
    
            // If it is not tracked by the context, add it to the context
            if (entry.State == EntityState.Detached)
            {
                // This also sets the entity state to added.
                context.Set<TEntity>().Add(entity);
            }
            else
            {
                // Tells the context that the entity should be updated during saving changes
                entry.State = EntityState.Modified;
            }
    
            // In a perfect world, you should use a decorator and save the changes there using Dependency Injection
            context.SaveChanges();
        }
    
        public void Delete(TEntity entity)
        {
            var context = _contextProvider();
            var entry = context.Entry(entity);
            if (entry.State != EntityState.Deleted)
            {
                // This also sets the entity state to Deleted.
                context.Set<TEntity>().Remove(entity);
            }
    
            // In a perfect world, you should use a decorator and save the changes there using Dependency Injection
            context.SaveChanges();
        }
    
        public TEntity Get(object primaryKey)
        {
            var context = _contextProvider();
            var entity = context.Set<TEntity>().Find(primaryKey);
            if (entity == null) return null;
    
            // We found the entity, set the state to unchanged.
            context.Entry(entity).State = EntityState.Unchanged;
    
            return entity;
        }
    }
    

    如果您正在使用依赖注入库,例如Simple Injector,您可以像这样连接它:

    container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);
    container.Register(typeof(IEntityWriter<>), typeof(EntityFrameworkWriter<>), Lifestyle.Scoped);
    container.Register(typeof(IEntityReader<>), typeof(EntityFrameworkReader<>), Lifestyle.Scoped);
    

相关问题