EF ObjectContext,服务和存储库 - 管理上下文生命周期。

7

我对MVP和Entity Framework还比较新,所以请多包涵。

目前我有一个视图+Presenter组合,视图有两个事件:编辑和删除,而Presenter只是监听这些事件。我还设置了服务对象和存储库。服务层采取一些存储库实现,这些实现采用ObjectContext,因此构建顺序为(将上层对象传递给下面的对象):

ObjectContext
   |
   V
Repositries
   |
   V
Service Object
   |
   V
Presenter

现在的问题是,当我在顶部创建对象上下文时,它会在整个presenter生命周期内保持活动状态,这意味着Edit和Delete使用来自service的相同上下文实例。
因此,调用ServiceObject.Delete和ServiceObject.Edit使用相同的上下文,这使得难以管理更改跟踪。据我了解,上下文实际上应该只存在短暂时间,并且仅用于工作单元,对我来说,Edit和Delete都是不同的工作单元。
如何使用entity framework进行DI并仍然管理上下文生命周期?
我看到有人在存储库内部新建对象上下文,这是一个好的模式吗?
还是应该在service对象中执行此操作,类似于:
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 :(.

在这种情况下我该怎么办?

有人知道任何开源项目可以帮助我解决这个问题吗?

谢谢。

1个回答

24
我将从主讲人的角度开始描述参与者之间的关系。
主讲人通过依赖获取服务对象。服务功能是根据其契约来概述的:
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
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接