2009-07-23 7 views
7

저는 MVP와 Entity Framework 세계에 새로운 편입니다.EF ObjectContext, 서비스 및 저장소 - 컨텍스트 수명 관리.

현재보기 + 발표자 조합이 있으며보기에는 수정 및 삭제라는 두 가지 이벤트가 있으며 발표자는이 이벤트를 수신합니다. 또한 서비스 개체와 저장소가 설정되어 있습니다. 서비스 층 구성의 순서는 (아래에있는 하나의 상단 오브젝트에 통과 그래서 ObjectContext를 가지고 어떤 저장소 구현 취

ObjectContext 
    | 
    V 
Repositries 
    | 
    V 
Service Object 
    | 
    V 
Presenter 

을 이제 문제임 I는 상단 오브젝트 컨텍스트를 만들면 발표자가 살아있는 동안 편집과 삭제가 서비스에서 동일한 컨텍스트 인스턴스를 사용한다는 것을 의미합니다.

따라서 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를하고 있지 않다 :

가 아니면 서비스 객체에 뭔가처럼 그렇게 없습니다.

나는이 상황에서 무엇을 할 수 있습니까?

사람이이 문제를 나에게 도움이 될 수 있습니다 내가 그 볼 수있는 오픈 소스 프로젝트를 알고 있나요.

감사합니다.

답변

24

저는 맨 (발표자)에서 참가자의 관계를 설명합니다.

Presenter는 종속성을 통해 서비스 개체를 가져옵니다. 서비스 기능은 계약을 통해 약술됩니다 :

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

서비스 구현은 특정 데이터 액세스 계층 구현에서 추상화됩니다. 기본적으로 서비스가 데이터 소스 상호 작용을 요구하는 일부 조치를 수행 할 때마다 작업 단위 (UOW)의 인스턴스를 작성하고 완료되면이를 처리합니다.

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를 전파하는 데 사용됩니다.

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

그 좋은 uuh :

여기 IUnitOfWork의 단순화 구현입니다! – Roubachof

관련 문제