簡體   English   中英

使用實現2個接口的EF DbContext進行依賴注入

[英]Dependency injection with EF DbContext that implements 2 interfaces

給定一個實現2個接口的DbContext,如下所示:

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,該DI目前使用IUnitOfWork接口的每HTTP上下文生存期注入MyDbContext。 我不確定如何為IQueryEntities接口設置注入,以便它將重用可能已經針對IUnitOfWork接口注入的現有DbContext實例。 或相反亦然。 這有可能嗎?

這是當前的生存期管理器,它在相同的http上下文中重用以前注入的IUnitOfWork實例:

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>

將DbContext(IDbSets)的查詢方面與命令方面(SaveChanges)分開是一個壞主意嗎?

我認為這是個好主意,因為有接口隔離原則 ,該原則規定每個客戶端僅應看到其工作所需的接口。

要注冊,我會做:

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>

您需要將一個接口注冊為單例,而另一個將自動跟隨。

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

假設您的LifetimeManager正常工作,這會將MyContext實例的生存期限MyContextHttpContext並且IUnitOfWork的映射將重用同一實例,因為映射的目標是相同的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM