[英]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,所以我實現了Repository
和UnitOfWork
模式,以便在需要時可以方便地換出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.Save
和OrdersService.SaveRange
都調用SaveChanges()
方法,但由於我將它們包裝在事務中,因此數據未提交到數據庫。
問題 :我應該向哪個LifeTimeManager注冊DbContext
, IUnitOfWork
和每個存儲庫?
在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.