我对MVP和实体框架世界相当新,所以请耐心等待。
我目前有一个View + Presenter组合,该视图有两个事件Edit和Delete,而演示者只是监听这些事件。我还有一个服务对象和存储库设置。服务层采用一些存储库实现,这些实现采用ObjectContext,因此构造的顺序是(将顶层对象传递给它下面的对象:
ObjectContext
|
V
Repositries
|
V
Service Object
|
V
Presenter
现在的问题是,当我在顶部创建对象上下文时,它一直存在,演示者处于活着状态,这意味着编辑和删除使用来自服务的相同上下文实例。
因此,调用ServiceObject.Delete和ServiceObject.Edit会使用相同的上下文,这使得很难管理更改跟踪。根据我的理解,上下文应该只是短暂的,只有一个工作单元,对我来说编辑和删除都是不同的工作。
如何使用实体框架进行DI并仍然管理上下文生命周期?
我看到人们刚刚在存储库中新建了对象上下文,这是一个很好的模式。
或者我应该在服务对象中执行此操作,例如:
ServiceObject{
public void Edit(// some args) {
Using(var context = new MyObjectContext) {
var repo = new MyRepo(context);
var entity = repo.GetForID(12);
// Do some stuff for edit
context.SaveChanges();
}
}
}
但是,如果我这样做,我不再将我的存储库传递给ServiceObject的构造函数而不执行DI :(。
在这种情况下我该怎么办?
有没有人知道我可以看到的任何开源项目可以帮助我解决这个问题。
感谢。
答案 0 :(得分:24)
我将从顶部(演示者)开始,描述参与者之间的关系。
Presenter通过依赖项获取服务对象。使用合同概述服务功能:
class Presenter
{
public Presenter(IService service)
{
...
}
}
从特定数据访问层实现中抽象出服务实现。基本上,每当服务执行一些需要数据源交互的操作时,它就会创建一个工作单元的实例,并在完成时将其处理掉。
interface IService
{
void Do();
}
class Service : IService
{
private readonly IUnitOfWorkFactory unitOfWorkFactory;
public Service(IUnitOfWorkFactory unitOfWorkFactory)
{
this.unitOfWorkFactory = unitOfWorkFactory;
}
public void Do()
{
// Whenever we need to perform some data manipulation we create and later dispose
// dispose unit of work abstraction. It is created through a factory to avoid
// dependency on particular implementation.
using(IUnitOfWork unitOfWork = this.unitOfWorkFactory.Create())
{
// Unit of work holds Entity Framework ObjectContext and thus it used
// create repositories and propagate them this ObjectContext to work with
IRepository repository = unitOfWork.Create<IRepository>();
repository.DoSomethingInDataSource();
// When we are done changes must be commited which basically means committing
// changes of the underlying object context.
unitOfWork.Commit();
}
}
}
/// <summary>
/// Represents factory of <see cref="IUnitOfWork"/> implementations.
/// </summary>
public interface IUnitOfWorkFactory
{
/// <summary>
/// Creates <see cref="IUnitOfWork"/> implementation instance.
/// </summary>
/// <returns>Created <see cref="IUnitOfWork"/> instance.</returns>
IUnitOfWork Create();
}
/// <summary>
/// Maintains a list of objects affected by a business transaction and coordinates the writing out of
/// changes and the resolution of concurrency problems.
/// </summary>
public interface IUnitOfWork : IDisposable
{
/// <summary>
/// Creates and initializes repository of the specified type.
/// </summary>
/// <typeparam name="TRepository">Type of repository to create.</typeparam>
/// <returns>Created instance of the repository.</returns>
/// <remarks>
/// Created repositories must not be cached for future use because once this
/// <see cref="IUnitOfWork"/> is disposed they won't be able to work properly.
/// </remarks>
TRepository Create<TRepository>();
/// <summary>
/// Commits changes made to this <see cref="IUnitOfWork"/>.
/// </summary>
void Commit();
}
/// <summary>
/// Represents factory of <see cref="UnitOfWork"/>s.
/// </summary>
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private readonly IUnityContainer container;
/// <summary>
/// Initializes a new instance of the <see cref="UnitOfWorkFactory"/> class.
/// </summary>
/// <param name="container">
/// Dependency injection container instance used to manage creation of repositories
/// and entity translators.
/// </param>
public UnitOfWorkFactory(IUnityContainer container)
{
this.conainer = container;
}
/// <summary>
/// Creates <see cref="IUnitOfWork"/> implementation instance.
/// </summary>
/// <returns>Created <see cref="IUnitOfWork"/> instance.</returns>
public IUnitOfWork Create()
{
var unitOfWork = this.container.Resolve<UnitOfWork>();
unitOfWork.SetupObjectContext();
return unitOfWork;
}
... other members elidged for clarity
}
IUnitOfWork的实现接收IUnityContainer的实例,然后创建子容器并在那里注册ObjectContext实例。此子容器将用于创建存储库并传播ObjectContext。
以下是IUnitOfWork的简化实现:
class UnitOfWork : IUnitOfWork
{
private readonly IUnityContainer container;
private ObjectContext objectContext;
public UnitOfWork (IUnityContainer container)
{
this.container = container.CreateChildContainer();
}
public void SetupObjectContext()
{
this.objectContext = ... // Create object context here
this.container.RegisterInstance(context.GetType(), context);
}
public void Create<TRepository>()
{
// As long as we registered created object context instance in child container
// it will be available now to repositories during resolve
return this.container.Resolve<TRepository>();
}
public void Commit()
{
this.objectContext.SaveChanges();
}
}
class Repository : IRepository
{
private readonly SomeObjectContext objectContext;
public Repository(SomeObjectContext objectContext)
{
this.objectContext = objectContext;
}
public void DoSomethingInDataSource()
{
// You can use object context instance here to do the work
}
}