繁体   English   中英

编写WPF应用程序时,我应该将哪个DbContext注册到Unity容器中?

[英]Which lifetime-manager do I register my DbContext into Unity container when writing a WPF application?

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

我正在使用Entity Framework Core与数据库进行交互。 但是,我不想将应用程序紧密耦合到Entity Framework Core,所以我实现了RepositoryUnitOfWork模式,以便在需要时可以方便地换出Entity Framework Core实现。

我的存储库实现提供了一个名为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()方法,但由于我将它们包装在事务中,因此数据未提交到数据库。

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

在Web环境中,我将使用PerRequestLifetimeManager注册所有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具有容器层次结构的概念,并且能够为每个视图创建容器范围,则在这种情况下可以使用单例,并且您不需要上面提到的任何抽象,这样会容易得多跟...共事。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM