依赖注入与EF的DbContext实现2接口 [英] Dependency injection with EF DbContext that implements 2 interfaces

查看:1633
本文介绍了依赖注入与EF的DbContext实现2接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于实现了像2接口的DbContext这样:

 公共接口IQueryEntities 
{
IQueryable的< ;使用者名称>用户{搞定; }
&IQueryable的LT;计算机及GT;计算机{搞定; }
//其他的IQueryable< T>获取属性
}

公共接口IUnitOfWork
{
INT的SaveChanges();
}

公共类MyContext:的DbContext,IQueryEntities,IUnitOfWork
{
//实现使用接口EF
}

第一个问题,它是一个坏主意的DbContext的查询方面(IDbSets)从命令方面(的SaveChanges)分离出来?我正在探索一个重构上面的,因为有很多,我们只需要查询数据的情况下,不保存任何东西。



我快到的问题涉及统一DI,目前使用的是单每HTTP的上下文生存期为IUnitOfWork接口注入MyDbContext。我不知道如何去建立注入了IQueryEntities接口,这样它会重复使用现有的,可能已经被注入对IUnitOfWork接口的DbContext实例。或相反亦然。 ?这甚至可能



下面是当前生命周期管理器重用IUnitOfWork先前注入的情况下,在同一个HTTP上下文:

 公共类UnityHttpContextLifetimeManager:LifetimeManager 
{
私人常量字符串KeyFormat =SingletonPerCallContext_ {0};
私人只读字符串_key;

公共UnityHttpContextLifetimeManager()
{
_key =的String.Format(KeyFormat,Guid.NewGuid());
}

公众覆盖对象的GetValue()
{
返回HttpContext.Current.Items [_key]
}

公共覆盖无效的SetValue(对象newValue)以
{
HttpContext.Current.Items [_key] =为newValue;
}

公共覆盖无效RemoveValue()
{
HttpContext.Current.Items.Remove(_key);
}
}



顺便说一句,如果有一种方法可以做到这一点,我宁愿做团结web.config部分,而不是编译的C#引导程序。



更新



从ONOF我能得到这个工作的帮助,但我的配置看起来与他的提议不同。难道我做错了什么?当我不给每个接口的生命周期管理,人们的HttpContext用的DbContext的多个实例结束。只有当我让所有3生命周期管理器做它跨越了两个接口一个请求重复使用相同的DbContext实例。 ?有什么问题与此配置。



 <统一的xmlns =http://schemas.microsoft.com/practices/2010 /统一> 
<命名空间名称=MyApp.MyNameSpace/>
<装配NAME =MyApp的/>
<别名别名为单身每HTTP上下文
型=MyApp.MyNameSpace.UnityHttpContextLifetimeManager,MyApp的/>
<集装箱>
<注册类型=MyContext>
<终身TYPE =单身每HTTP上下文/>
< /注册>
<注册类型=IUnitOfWorkmapTo =MyContext>
<终身TYPE =单身每HTTP上下文/>
< /注册>
<注册类型=IQueryEntitiesmapTo =MyContext>
<终身TYPE =单身每HTTP上下文/>
< /注册>

< /容器>


解决方案

它是一个坏的主意的DbContext
的查询方面(IDbSets)从命令方面(的SaveChanges)分离出来?




我认为这是一个好主意,因为接口隔离原则的,其中规定,每个客户端应该只看到它的界面。需要做的工作。



要注册,我会做:

  container.RegisterType&所述; MyContext>(新UnityHttpContextLifetimeManager()); 
container.RegisterType< IQueryEntities,MyContext>();
container.RegisterType< IUnitOfWork,MyContext>();



据我所知它是共享同一个实例的唯一途径,一旦对象创建的。



要在设计时(在web.config中)做到这一点,这是简单的:

 <统一的xmlns =http://schemas.microsoft.com/practices/2010/unity> 
<命名空间名称=MyApp.MyNameSpace/>
<装配NAME =MyApp的/>
<集装箱>
<注册类型=MyContext>
<终身TYPE =UnityHttpContextLifetimeManager/>
< /注册>
<注册类型=IQueryEntitiesmapTo =MyContext/>
<注册类型=IUnitOfWorkmapTo =MyContext/>
< /容器>


Given a DbContext that implements 2 interfaces like so:

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
}

First question, is it a bad idea to separate out the query aspects of DbContext (IDbSets) from the command aspects (SaveChanges)? I am exploring a refactor to the above because there are a lot of cases where we just need to query data, without saving anything.

The problem I'm running into involves unity DI, which currently injects MyDbContext using a singleton-per-http-context lifetime for the IUnitOfWork interface. I'm not sure how to go about setting up injection for the IQueryEntities interface so that it will reuse an existing DbContext instance that may have already been injected against the IUnitOfWork interface. Or vice versa. Is this even possible?

Here is the current lifetime manager that reuses previously-injected instances of IUnitOfWork in the same http context:

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

By the way if there is a way to do this, I would prefer to do it in unity web.config section rather than compiled c# bootstrapper.

Update

With help from onof I was able to get this working, however my config looks different from what he suggested. Am I doing something wrong? When I don't give each interface the lifetime manager, one HttpContext ends up with multiple instances of the DbContext. Only when I give all 3 the lifetime manager does it reuse the same DbContext instance across a single request for both interfaces. Is something wrong with this config?

<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>

解决方案

is it a bad idea to separate out the query aspects of DbContext (IDbSets) from the command aspects (SaveChanges)?

I think it's a good idea, because of Interface Segregation Principle, which states that each client should see only the interface it needs to do its work.

To register, i would do:

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

AFAIK it's the only way to share the same instance, once the object created.

To do it at design-time (in web.config), it's straightforward:

<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>

这篇关于依赖注入与EF的DbContext实现2接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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