简体   繁体   English

在MVC 4应用程序中使用Unity with Entity Framework的最佳实践是什么

[英]What is best practice for using Unity with Entity Framework in a MVC 4 application

I'm struggling with Entityframework in a MVC 4 app, making use of Unity for Dependency injection and Automapper for automapping object to DTO. 我正在努力使用MVC 4应用程序中的Entityframework,利用Unity for Dependency注入和Automapper将对象自动化到DTO。 I run from one issue to the other, EF is sometimes returning old data, so I think my design is not good enough. 我从一个问题跑到另一个问题,EF有时会返回旧数据,所以我认为我的设计不够好。

What do I have: 我有什么:

To configure Unity I have in my Application_Start: 要在我的Application_Start中配置Unity:

var UnityContainer = UnityConfig.GetConfiguredContainer();
Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityContainer.Resolve(type)));
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();
...

In UnityConfig.RegisterTypes: 在UnityConfig.RegisterTypes中:

container.RegisterType<IMyContext, MyContext>(new ContainerControlledLifetimeManager())
...

My respositories use constructor depencency injection: 我的存储库使用构造函数依赖注入:

public class MSSQLTenantRepository : IDalTenantRepository
{
   private readonly IMyContext _Db;
   public MSSQLTenantRepository(IMyContext db)
   {
      Db = db;
   }
...

And my controller use constructor dependency injection too: 我的控制器也使用构造函数依赖注入:

public class TenantController : Controller
{
   private readonly ITenantRepository _TenantRepository;
   public TenantController(ITenantRepository tenantRepository,
   {
      _TenantRepository = tenantRepository;
   }
...

Automapper config: 自动配置配置:

public class AutoMapperConfig
{
    private readonly ITenantRepository _TenantRepository;
    public AutoMapperConfig(ITenantRepository tenantRepository)
    {
        _TenantRepository = tenantRepository;
    }
...

Issues: I sometimes get old data, from the first request. 问题:我有时会从第一个请求中获取旧数据。

When I manually update the data in de SQL server, EF's returning object don't reflect the changes 当我手动更新de SQL Server中的数据时,EF的返回对象不会反映更改

When I tried different options I also got error about multiple context (due to Automapper) 当我尝试不同的选项时,我也遇到了关于多个上下文的错误(由于Automapper)

My questions: 我的问题:

  • What is best practice using Unity, MVC4, EF 6, repositories and Automapper? 使用Unity,MVC4,EF 6,存储库和Automapper的最佳做法是什么?
  • Where to put the code (eg in global.asax.c or in UnitiConfig.cs of UnityWebApiActivator? 放置代码的位置(例如,在Unity.AaxActivator的global.asax.c或UnitiConfig.cs中?
  • Do I need to explicit dispose the dbcontext, and if so: Where to do this? 我是否需要显式处理dbcontext,如果是这样的话:在哪里这样做?

There is a lot said about this subject, but nothing covers all. 关于这个主题有很多说法,但没有任何内容涵盖所有内容。

 container.RegisterType<IMyContext, MyContext>(
     new ContainerControlledLifetimeManager())

This is rather bad, it makes a singleton out of your context. 这是相当糟糕的,它使你的上下文成为一个单例。 This way not only multiple requests share the same context and you risk concurrency issues but also the memory consumption of such shared context grows without control. 这样,不仅多个请求共享相同的上下文,而且存在并发问题的风险,而且这种共享上下文的内存消耗也会在没有控制的情况下增长。

Rather, you would like to have a "per-request" life time, where a new context is established for each separate request: 相反,您希望有一个“按请求”的生命周期,其中为每个单独的请求建立新的上下文:

http://www.wiktorzychla.com/2013/03/unity-and-http-per-request-lifetime.html http://www.wiktorzychla.com/2013/03/unity-and-http-per-request-lifetime.html

public class PerRequestLifetimeManager : LifetimeManager
{
  private readonly object key = new object();

  public override object GetValue()
  {
    if (HttpContext.Current != null && 
        HttpContext.Current.Items.Contains(key))
        return HttpContext.Current.Items[key];
    else
        return null;
  } 

  public override void RemoveValue()
  {
    if (HttpContext.Current != null)
        HttpContext.Current.Items.Remove(key);
  }

  public override void SetValue(object newValue)
  {
    if (HttpContext.Current != null)
        HttpContext.Current.Items[key] = newValue;
  }
}

and

container.RegisterType<IMyContext, MyContext>(new PerRequestLifetimeManager())

I am not sure what your AutoMapperConfig class does and why a repository is injected into it. 我不确定您的AutoMapperConfig类的作用以及为什么要将存储库注入其中。 This is a possible another lifetime issue but I need a clarification on that. 这可能是另一个终身问题,但我需要澄清一下。

I figured it out with some help of Wiktor. 我在Wiktor的帮助下弄明白了。

First: I must just a PerRequestLifeTimeManager (as stated by Wiktor Zychla, thank you for that), which is available in de Unity for MVC bootstrapper. 第一:我必须只是一个PerRequestLifeTimeManager(如Wiktor Zychla所述,谢谢你),这可以在de Unity for MVC bootstrapper中找到。

Second: The line: 第二:行:

UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();

must be in Application_BeginRequest (Globas.asax.cs). 必须在Application_BeginRequest(Globas.asax.cs)中。 I've put it in Application_Start, so this was only resolved once at startup. 我把它放在Application_Start中,所以这只在启动时解决了一次。 An incoming request was creating a new context, so it differs from the one that Automapper uses. 传入请求正在创建新上下文,因此它与Automapper使用的不同。 When putting it in BeginRequest the resolve is done on every request, with the same context as the repositories. 将其放入BeginRequest时,将对每个请求执行解析,并使用与存储库相同的上下文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM