【问题标题】:EF ObjectContext, Service and Repository - Managing context lifetime.EF ObjectContext、Service 和 Repository - 管理上下文生命周期。
【发布时间】:2009-07-23 01:54:14
【问题描述】:

我对 MVP 和实体框架世界还很陌生,所以请多多包涵。

我目前有一个 View + Presenter 组合,该视图有两个事件 Edit 和 Delete 并且 Presenter 只是监听这些事件。我还设置了一个服务对象和存储库。服务层采用一些采用 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 :(。

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

有谁知道我可以查看的任何开源项目可以帮助我解决这个问题。

谢谢。

【问题讨论】:

    标签: c# entity-framework dependency-injection


    【解决方案1】:

    我将从顶部(演示者)开始描述参与者之间的关系。

    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
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多