在分层项目中创建新实体而不会迷失在多个 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();
我有一个非常简单的 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();