在编写WPF应用程序时,我将DbContext注册到Unity容器中的哪个生命周期管理器?

时间:2018-05-22 22:06:48

标签: c# wpf repository entity-framework-core prism

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

我正在使用Entity Framework Core与数据库进行交互。但是,我不想将我的应用程序紧密地耦合到Entity Framework Core,因此我实现了RepositoryUnitOfWork模式,以便我可以在需要时更换实体框架核心实现。 / p>

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

此外,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()方法,但数据未提交到数据库,因为我用事务包装它们。

问题DbContext我应该注册IUnitOfWorkDbContext和每个存储库?

在网络环境中,我会使用LifeTimeManager注册所有内容然后在请求期间我重复使用相同的DbContext并且一切正常并且SaveChanges()被放置在结尾处http请求。但不确定如何在WPF应用程序中注册所有内容,我仍然可以使用事务来控制所有内容,同时允许存储库调用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;
    }
}

这是我的工作单元实施

tableView.setContentOffset(CGPoint(x: 0, y: -141), animated: true)

1 个答案:

答案 0 :(得分:0)

如果您的DI不支持作用域,那么

Transient(每个视图的一个实例)生命周期将会成为现实,但是你需要抽象出你的DbContext被传递到repo&unit和unitOfWork ,否则将在那里传递DbContext的新实例。在构建页面时,会创建一个新实例,并且在远离该视图时,应该丢弃该DBContext。 UnitOfWork将遵循相同的路径,因为您不希望UnitOfWork跨越DBContext的多个实例。 见http://blogs.microsoft.co.il/gilf/2010/02/07/entity-framework-context-lifetime-best-practices/。否则,如果您的DI具有容器层次结构的概念,并且您能够为每个视图创建容器范围,那么单例将在此实例中起作用,您将不需要上面提到的任何抽象,并且将是使用起来相当容易。