EF阅读&写入CQRS的模式

时间:2016-03-22 08:45:34

标签: .net entity-framework dapper cqrs

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

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

1 个答案:

答案 0 :(得分:2)

对于实体框架,您的应用程序中应该只有一个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);