EF ObjectContext,服务和资源库 - 管理上下文生命周期。 [英] EF ObjectContext, Service and Repository - Managing context lifetime.

查看:144
本文介绍了EF ObjectContext,服务和资源库 - 管理上下文生命周期。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对MVP和实体框架世界是相当新的,所以我一直忍受。



我目前有一个View + Presenter组合,该视图有两个事件编辑而删除和演示者只是听这些事件。我也有一个服务对象和存储库设置。服务层采取一些存储库实现,它采用一个ObjectContext,所以构造的顺序是(将顶层对象传递到下面的对象:

  ObjectContext 
|
V
Repositries
|
V
服务对象
|
V
演示者

现在的问题是当我在顶部创建对象上下文时,它一直活着演示者活着意味着编辑和删除使用与服务相同的上下文实例。



所以调用ServiceObject.Delete和ServiceObject.Edit使用相同的上下文,这使得很难管理变更跟踪从我理解的情况应该只是短暂的,只有一个单位的工作,对我来说,编辑和删除都是不同的工作。



您如何使用实体框架DI来处理上下文生命周期?



我已经看到人们刚刚创建了objec或者我应该在服务对象中这样做,例如:


$($)
$ b b $ b

  ServiceObject {
public void Edit(// some args){
Using(var context = new MyObjectContext){
var repo = new MyRepo(context);
var entity = repo.GetForID(12);
//做一些编辑的东西
context.SaveChanges();
}
}
}

但是如果我这样做我不再将我的存储库传递给ServiceObject的构造函数,而不是执行DI :(。



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



有人知道任何可以看到的开源项目可能会帮助我解决这个问题。



谢谢。

解决方案

我将从顶部(主持人)开始介绍参与者之间的关系。



Presenter通过依赖获取服务对象,服务功能概述是使用其合同:

  class Presenter 
{
公开演讲者(IService服务)
{
...
}
}

服务实现是从特定的数据访问层实现中抽象的,基本上每当服务执行一些需要数据源交互的操作时,它创建一个单元的实例的工作,并在完成后将其处理。

 接口IService 
{
void Do();
}

class服务:IService
{
private readonly IUnitOfWorkFactory unitOfWorkFactory;
public Service(IUnitOfWorkFactory unitOfWorkFactory)
{
this.unitOfWorkFactory = unitOfWorkFactory;
}

public void Do()
{
//每当我们需要执行一些数据操作,我们创建并稍后处理
//处理单元的工作抽象。它是通过工厂创建的,以避免
//依赖于特定的实现。
使用(IUnitOfWork unitOfWork = this.unitOfWorkFactory.Create())
{
//工作单位保留Entity Framework ObjectContext,因此它使用
//创建存储库并传播它们这个ObjectContext使用
IRepository repository = unitOfWork.Create< IRepository>();
repository.DoSomethingInDataSource();

//当我们完成更改时,必须被提交,这基本上意味着提交
//底层对象上下文的更改。
unitOfWork.Commit();
}
}
}


///< summary>
///表示工厂的&​​lt; see cref =IUnitOfWork/>实现。
///< / summary>
public interface IUnitOfWorkFactory
{
///< summary>
///创建< see cref =IUnitOfWork/>实施实例。
///< / summary>
///< returns>创建< see cref =IUnitOfWork/>实例< /回报>
IUnitOfWork Create();
}

///< summary>
///维护受业务事务影响的对象的列表,并协调写入
///更改和解决并发问题。
///< / summary>
public interface IUnitOfWork:IDisposable
{
///< summary>
///创建并初始化指定类型的存储库。
///< / summary>
///< typeparam name =TRepository>要创建的存储库类型。< / typeparam>
///< returns>存储库的创建实例。< / returns>
///< remarks>
///创建的存储库不能被缓存以备将来使用,因为一旦这个
///< see cref =IUnitOfWork/>被处置,他们将无法正常工作。
///< / remarks>
TRepository创建< TRepository>();

///< summary>
///提交对此的更改< see cref =IUnitOfWork/> ;.
///< / summary>
void Commit();
}

///< summary>
///表示< see cref =UnitOfWork/> s的工厂。
///< / summary>
public class UnitOfWorkFactory:IUnitOfWorkFactory
{
private readonly IUnityContainer container;

///< summary>
///初始化< see cref =UnitOfWorkFactory/>的新实例类。
///< / summary>
///< param name =container>
///用于管理创建存储库的依赖注入容器实例
///和实体翻译器。
///< / param>
public UnitOfWorkFactory(IUnityContainer container)
{
this.conainer = container;
}


///< summary>
///创建< see cref =IUnitOfWork/>实施实例。
///< / summary>
///< returns>创建< see cref =IUnitOfWork/>实例< /回报>
public IUnitOfWork Create()
{
var unitOfWork = this.container.Resolve< UnitOfWork>();
unitOfWork.SetupObjectContext();
return unitOfWork;
}

...其他成员清除
}

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 = ... //在此创建对象上下文
this.container.RegisterInstance( context.GetType(),context);
}

public void创建< TRepository>()
{
//只要我们在子容器中注册了创建的对象上下文实例
//解析过程中现在可以使用存储库
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()
{
//您可以在这里使用对象上下文实例来完成工作
}
}


I am fairly new to the MVP and the Entity Framework world so bear with me.

I currently have a View + Presenter combination, the view has two events Edit and Delete and the presenter just listens for these events. I also have a service object and repositories set up. The service layer takes some repository implementations which take an ObjectContext so the order of construction is (passing in the top object to the one below it:

ObjectContext
   |
   V
Repositries
   |
   V
Service Object
   |
   V
Presenter

Now the problem is that when I create object context at the top, It's alive for the whole time the presenter is alive meaning that Edit and Delete use the same context instance from the service.

So calling ServiceObject.Delete and ServiceObject.Edit use the same context which makes it hard to manage change tracking. From what I understand the context should really only be short lived and only for a unit of work, to me Edit and Delete are both different lots of work.

How do you do DI with the entity framework and still manage context life time?

I have seen people just new up the object context in side the repository, is this a good pattern.

Or should I do that in the service object, something like:

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();
     }
  }
}

But If I do it like that I am no longer passing my repository into the constructor of ServiceObject and not doing DI :(.

What can I do in this situation?

Does anyone know any open source projects that I can look at that may help me with this problem.

Thanks.

解决方案

I will go from top (presenter) and describe the relations between participants.

Presenter gets service object through dependency. Service functionality is outlined using its contract:

class Presenter 
{
  public Presenter(IService service)
  {
     ... 
  }
}

Service implementation is abstracted from particular data access layer implementation. Basically whenever service performs some action that requires data source interaction it creates an instance of unit of work and disposes it when it finished.

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
}

The implementation of IUnitOfWork receives instance of IUnityContainer and then creates child container and registers ObjectContext instance there. This child container will be used to create repositories and propagate ObjectContext.

Here is a simplified implementation of 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
  }
}

这篇关于EF ObjectContext,服务和资源库 - 管理上下文生命周期。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆