我已经读过Dapper一般比EF快得多,并且正在考虑使用Dapper作为查询端,EF考虑使用CQRS(lite)模式的应用程序写入端。
但是,我也知道EF可以默认关闭跟踪功能。是否值得创建2个数据库上下文,一个用于在所有实体中启用AsNoTracking进行阅读,另一个用于在启用跟踪的情况下进行写入?这样,我可以在不使用其他库的情况下获得性能优势,并增加额外的复杂性。
答案 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);