编写 WPF 应用程序时,应将 DbContext 注册到哪个生存期管理器中?



我正在使用众所周知的MVVM设计模式在Prism 6.3框架之上编写一个新的C#应用程序。我正在使用 Unity IoC 容器来帮助我管理依赖项。

我正在使用实体框架核心与数据库进行交互。但是,我不想将我的应用程序与实体框架核心紧密耦合,因此我实现了RepositoryUnitOfWork模式,以便在需要时轻松换出实体框架核心实现。

我的存储库实现提供了一个名为Save()的方法,该方法调用 EF Core 的SaveChanges()方法。存储库被注入到我的业务服务中,以便我的业务服务公开一种方法来执行单个任务。例如,如果我想创建一个新订单,我会调用内部调用Add()Create(orderViewModel)方法和OrderRepository上的Save()方法。

此外,UnitOfWork还提供了Save()BeginTransaction()Commit()Rollback()方法,允许我控制交易行为。换句话说,它将使我能够在需要时灵活地提交或回滚SQL事务。

为了更好地解释我的用例,下面是一个示例,说明我如何使用业务服务直接向数据库添加新订单,而无需事务或工作单元。

OrdersService.Create(orderViewModel); // this will call the `Add` and the `Save()` methods on the OrderRepository;

这是另一个示例,演示了我如何使用业务服务将新订单和订单项添加到我的数据库中,同时使用工作单元启动事务并控制事务。

using(var transaction = UnitOfWork.BeginTransaction())
{
try 
{
var order = OrdersService.Create(orderViewModel);
OrdersService.CreateRange(order.Id, orderItemsViewModel);
transaction.Commit();
} 
catch(Exception e)
{
Log.Add(e);
transaction.RollBack();
}
}

在上面的第二个示例中,即使OrdersService.SaveOrdersService.SaveRange分别调用SaveChanges()方法,数据也不会提交到数据库,因为我用事务包装它们。

问题:我应该用哪个 LifeTimeManager 注册DbContextIUnitOfWork和我的每个存储库?

在 Web 环境中,我会使用PerRequestLifetimeManager注册所有内容,然后在请求期间我重复使用相同的DbContext并且一切正常,并且DbContext在 http 请求结束时被处理。但是不确定如何在 WPF 应用程序中注册所有内容,我仍然可以使用事务来控制所有内容,同时允许存储库调用SaveChanges()

如果需要,这里是我的EntityRepository实现

public class EntityRepository<TEntity, TKeyType> : IRepository<TEntity, TKeyType>
where TEntity : class
where TKeyType : struct
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(TKeyType id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public bool Any(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Any(predicate);
}
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public virtual TEntity Add(TEntity entity)
{
var record = Context.Add(entity);
record.State = EntityState.Added;
return entity;
}
public virtual IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
{
Context.AddRange(entities);
return entities;
}
public void Remove(TEntity entity)
{
Context.Remove(entity).State = EntityState.Deleted;
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
Context.RemoveRange(entities);
}
public void Update(TEntity entity)
{
DbSet.Attach(entity);
var record = Context.Entry(entity);
record.State = EntityState.Modified;
}
public IQueryable<TEntity> Query()
{
return DbSet;
}
public void Save()
{
Context.SaveChanges();
}
}

这是我的工作单元实施

public sealed class UnitOfWork : IUnitOfWork
{
private bool IsDisposed = false;
private readonly DbContext Context;
public IOrderRepository Orders { get; private set; }
public IOrderItemRepository OrderItems { get; private set; }
public UnitOfWork(DbContext context)
{
Context = context;
Orders = new OrderRepository(context);
OrderItems = new OrderItemRepository(context);
}
public int Save()
{
Context.SaveChanges();
return 0;
}
public void Dispose()
{
Dispose(true);
}
public IDatabaseTransaction BeginTransaction()
{
return new EntityDatabaseTransaction(Context);
}
private void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
if (disposing)
{
Context.Dispose();
}
IsDisposed = true;
}
}

如果您的 DI 不支持作用域,则瞬态(每个视图一个实例(生存期将是要走的路,但随后您需要将传递到存储库和 unitOfWork 中的 DbContext 抽象出来,否则 DbContext 的新实例将传入其中。在构建页面时,将创建一个新实例,并且在离开该视图时,应释放该 DBContext。UnitOfWork 将遵循相同的路径,因为您不希望 UnitOfWork 跨越 DBContext 的多个实例。 请参阅 http://blogs.microsoft.co.il/gilf/2010/02/07/entity-framework-context-lifetime-best-practices/。否则,如果你的 DI 具有容器层次结构的概念,并且你能够为每个视图创建一个容器范围,那么单例将在此实例中工作,并且你不需要上面提到的任何抽象,并且会更容易使用。

最新更新