在分层项目中创建新实体,而不会在多个HttpContext会话中丢失

时间:2017-12-19 07:28:23

标签: c# asp.net-mvc entity-framework httpcontext

我有一个非常简单的ASP.NET MVC项目,使用Entity Framework和Entities-> Repositories-> Services-> Controllers->视图分层结构构建。使用依赖注入。

我需要在我的控制器逻辑中做这样的事情(例如简化):

           var keyWord = _keywordService.GetByName("blah"); // Service instances are registered by dependency injection
           var myFile = new MyFile()
            {
                FileName = "//FilePath/etc"
            };               
           var myContent = new MediaContent()
            {
                UploadedFile = myFile
            };
           myContent.KeyWords.Add(keyword);
           _MediaContentService.AddContent(myContent); // Service instances are registered by dependency injection

但我不能。这不起作用,因为显然每次创建对象的新实例(myFileMyContent)时,都会使用它创建一个新的DBContext会话。因此,当我尝试保存myContent时,从示例中,多个上下文发生冲突,最后我收到了两条错误消息之一:

a)IEntityChangeTracker的多个实例无法引用实体对象。 要么 b)无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象。

我明白为什么会这样。每次创建EF实体的新实例时,都会调用DBContext初始化程序并创建新的Context。这可以避免吗? 这是我的自定义DBContext:

public class MyCustomDBContext : IdentityDbContext<ApplicationUser>
{
    public MyCustomDBContext (): base("ConnStringName", throwIfV1Schema: false){}

    public static MyCustomDBContext Create()
    {
        return new MyCustomDBContext();
    }
            public DbSet<FirstEntity> FirstEntity{ get; set; }
            //Other entities
            .
            .
            .

}

以下是Startup.Auth最初初始化该调用的方式。这就是应用程序知道如何根据请求创建新上下文的方式:

   public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context to use a single instance per request
        app.CreatePerOwinContext(MyCustomDBContext.Create);
    }

看起来Create()方法不断初始化新的Context实例......我不明白如何在不打破关注点分离的情况下解决它?我不想在应用程序的所有层周围传递DBContext的现有实例。 例如,与This问题一样,提供了在控制器中创建DBContext实例然后将其传递给服务,存储库等的建议。此建议不适用于内置的MVC基础结构。

正如我在第一个示例中尝试的那样,如何创建,处理和链接新对象,然后将它们发送到要保存的服务而不会在多个上下文中丢失?毕竟,每个请求我应该只有一个上下文。

2 个答案:

答案 0 :(得分:0)

您应该使用 using 关键字作为解决方案,这将解决您的问题。我在我的项目中使用多个上下文:

using (MyFile myFile = new MyFile()) 
{
   using(MediaContent myContent = new MediaContent())
   {
     myFile.FileName = "//FilePath/etc";  
     myContent.UploadedFile = myFile;   

       myContent.KeyWords.Add(keyword);
      _MediaContentService.AddContent(myContent);  
   }
}

答案 1 :(得分:0)

解决方案是在依赖注入映射文件中为DBContext创建一个映射:

kernel.Bind<MyCustomDBContext>().ToSelf().InRequestScope();