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

Creating new entities in a layered project without getting lost in multiple HttpContext sessions

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

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

           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

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

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

我明白为什么会这样。每次创建 EF 实体的新实例时,都会调用我的 DBContext 初始值设定项并创建一个新的上下文。这可以避免吗? 这是我的自定义 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 基础结构。

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

您应该做的是,使用 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);  
   }
}

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

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