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映射将重复使用相同的实例作为映射的目标是相同的。