1

由於實現了2個接口,就像這樣的DbContext:依賴注入EF的DbContext實現2個接口

public interface IQueryEntities 
{ 
    IQueryable<User> Users { get; } 
    IQueryable<Computer> Computers { get; } 
    // other IQueryable<T> get properties 
} 

public interface IUnitOfWork 
{ 
    int SaveChanges(); 
} 

public class MyContext : DbContext, IQueryEntities, IUnitOfWork 
{ 
    // implement interfaces using EF 
} 

第一個問題,它是一個壞主意,分離出從的DbContext(IDbSets)的查詢方面命令方面(SaveChanges)?我正在探索對上述的重構,因爲有很多情況下我們只需要查詢數據而不保存任何內容。

我遇到的問題涉及到統一DI,它目前使用IUnitOfWork接口的singleton-per-http-context生命週期注入MyDbContext。我不確定如何設置IQueryEntities接口的注入,以便它將重用已經注入到IUnitOfWork接口的現有DbContext實例。或相反亦然。這甚至有可能嗎?

這是當前生命週期管理器重用IUnitOfWork先前注入的情況下,在同一個HTTP上下文:

public class UnityHttpContextLifetimeManager : LifetimeManager 
{ 
    private const string KeyFormat = "SingletonPerCallContext_{0}"; 
    private readonly string _key; 

    public UnityHttpContextLifetimeManager() 
    { 
     _key = string.Format(KeyFormat, Guid.NewGuid()); 
    } 

    public override object GetValue() 
    { 
     return HttpContext.Current.Items[_key]; 
    } 

    public override void SetValue(object newValue) 
    { 
     HttpContext.Current.Items[_key] = newValue; 
    } 

    public override void RemoveValue() 
    { 
     HttpContext.Current.Items.Remove(_key); 
    } 
} 

順便說一句,如果有一種方法可以做到這一點,我寧願做在統一的web.config部分,而不是編譯的C#bootstrapper。

更新

與ONOF我能得到這個工作的幫助,但我的配置看起來與他的提議不同。難道我做錯了什麼?當我沒有爲每個接口提供生命期管理器時,一個HttpContext最終會包含多個DbContext實例。只有當我給全部3個生命管理器時,它纔會在兩個接口的單個​​請求中重複使用相同的DbContext實例。這個配置有問題嗎?

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> 
    <namespace name="MyApp.MyNameSpace" /> 
    <assembly name="MyApp" /> 
    <alias alias="singleton-per-http-context" 
     type="MyApp.MyNameSpace.UnityHttpContextLifetimeManager, MyApp" /> 
    <container> 
     <register type="MyContext"> 
      <lifetime type="singleton-per-http-context" /> 
     </register> 
     <register type="IUnitOfWork" mapTo="MyContext"> 
      <lifetime type="singleton-per-http-context" /> 
     </register> 
     <register type="IQueryEntities" mapTo="MyContext"> 
      <lifetime type="singleton-per-http-context" /> 
     </register> 
     ... 
    </container> 

回答

3

它是一個壞主意的DbContext 的查詢方面(IDbSets)從命令方面(的SaveChanges)分離出來?

我認爲這是一個好主意,因爲Interface Segregation Principle,其中規定每個客戶端應該只看到它的工作所需的接口。

要註冊,我會做:

container.RegisterType<MyContext>(new UnityHttpContextLifetimeManager()); 
container.RegisterType<IQueryEntities, MyContext>(); 
container.RegisterType<IUnitOfWork, MyContext>(); 

AFAIK它是共享同一個實例的唯一途徑,一旦對象創建的。

要在設計時(在web.config中)做到這一點,這是簡單的:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> 
    <namespace name="MyApp.MyNameSpace" /> 
    <assembly name="MyApp" /> 
    <container> 
     <register type="MyContext" >  
     <lifetime type="UnityHttpContextLifetimeManager" /> 
     </register> 
     <register type="IQueryEntities" mapTo="MyContext" /> 
     <register type="IUnitOfWork" mapTo="MyContext" /> 
    </container> 
+0

感謝ONOF。這很接近,但它似乎只在給予全部3生命管理器--DbContext和兩個接口時才起作用。看到我更新的問題。任何想法爲什麼這有效,但你的配置會導致創建單獨的實例? – danludwig 2012-01-31 12:16:50

+0

我認爲你是正確的。我錯過了其他註冊的生命。我會更新這個問題 – onof 2012-01-31 17:50:22

2

您需要將一個接口註冊爲單例,另一個接口將自動跟隨。

container.RegisterType<IQueryEntities, MyContext>(new UnityHttpContextLifetimeManager()); 
container.RegisterType<IUnitOfWork, MyContext>(); 

假設你LifetimeManager正常工作本就範圍MyContext一個實例的生命週期到HttpContextIUnitOfWork映射將重複使用相同的實例作爲映射的目標是相同的。