[英]How do I gracefully reattach an Entity Framework 5 POCO structure and save it?
I am making an MVC4 web application using Entity Framework 5 (Database-first with generated POCOs) for data access. 我正在使用Entity Framework 5(数据库优先生成生成的POCO)制作MVC4 Web应用程序以进行数据访问。
In the app, the user goes through several screens, creating or editing a document (called a 'case study'). 在该应用程序中,用户浏览多个屏幕,创建或编辑文档(称为“案例研究”)。 When they arrive at the final screen, their document exists as a CaseStudy POCO in memory, and everything is great until it is time to save this structure to the database.
当他们到达最后一个屏幕时,他们的文档以CaseStudy POCO的形式存在于内存中,并且一切都很好,直到需要将该结构保存到数据库中为止。
To store the document, I have defined several database tables, which in turn map to EF POCOs used by the business layer, which is then consumed by the MVC controllers. 为了存储文档,我定义了几个数据库表,这些表又映射到业务层使用的EF POCO,然后由MVC控制器使用。 As such, short-lived DbContexts are used to retrieve POCOs and store them in session between requests.
这样,短暂的DbContext用于检索POCO,并将它们存储在请求之间的会话中。
As a result, the save screen must save the contents of this POCO that has navigational properties to existing table data (Category, Layout, and Sections tables), and also added or updated data (CaseStudySections and the CaseStudy itself). 结果,保存屏幕必须将该具有导航属性的POCO的内容保存到现有表数据(Category,Layout和Sections表),以及添加或更新的数据(CaseStudySections和CaseStudy本身)。 So all of the POCOs are either new, or the context used to retrieve them has long been disposed.
因此,所有POCO都是新的,或者长期以来一直没有使用用于检索它们的上下文。 In other words, they are all 'detached'.
换句话说,它们都是“分离的”。
What is unusual about this post is that I already have a working solution in hand. 这篇文章不同寻常的是,我已经有了一个可行的解决方案。 The problem is that it is bulky, brittle, and inelegant.
问题在于它笨重,脆弱且不雅致。 I am posting the code below.
我在下面发布代码。 Note the iteration through sub-collections, the explicit adds and attaches, having to get an entry object and mark individual properties as modified just so they will be updated, and the awful song and dance at the end to get the AdditionalMaterials collection synced up.
请注意通过子集合进行的迭代,显式的添加和附加,必须获取一个入口对象并将单个属性标记为已修改,以便它们将被更新,最后的糟糕的歌舞动起来才能使AdditionalMaterials集合同步。 If this is what is required to deal with detached POCOs in EF5 I will be disappointed.
如果这是处理EF5中独立POCO的要求,我将感到失望。
Am I missing something here? 我在这里想念什么吗? Is this consistent with best practices?
这与最佳做法一致吗? Is there a more graceful and/or concise way to attach a structure of POCOs and insert/update?
有没有更优雅和/或更简洁的方法来附加POCO结构并进行插入/更新?
The code to save a case study: 保存案例研究的代码:
public void SaveCaseStudy(CaseStudy caseStudy)
{
foreach (var s in caseStudy.CaseStudySections)
{
this.Entities.Sections.Attach(s.Section);
if (s.CreatedByRefId == default(Guid))
{
s.CreatedByRefId = this.UserRefId;
s.CreatedTime = DateTime.Now;
this.Entities.CaseStudySections.Add(s);
}
else
{
this.Entities.CaseStudySections.Attach(s);
var entry = this.Entities.Entry(s);
entry.Property(e => e.TextData).IsModified = true;
entry.Property(e => e.BinaryData).IsModified = true;
}
s.LastModifiedByRefId = this.UserRefId;
s.LastModifiedTime = DateTime.Now;
}
foreach (var m in caseStudy.AdditionalMaterials)
{
if (m.CreatedByRefId == default(Guid))
{
m.CreatedByRefId = this.UserRefId;
m.CreatedTime = DateTime.Now;
this.Entities.AdditionalMaterials.Add(m);
}
else
{
this.Entities.AdditionalMaterials.Attach(m);
}
m.LastModifiedByRefId = this.UserRefId;
m.LastModifiedByTime = DateTime.Now;
}
this.Entities.Layouts.Attach(caseStudy.Layout);
this.Entities.Categories.Attach(caseStudy.Category);
if (caseStudy.CreatedByRefId != default(Guid))
{
this.Entities.CaseStudies.Attach(caseStudy);
var entry = this.Entities.Entry(caseStudy);
entry.Property(e => e.CaseStudyName).IsModified = true;
entry.Property(e => e.CaseStudyTitle).IsModified = true;
}
else
{
this.Entities.CaseStudies.Add(caseStudy);
caseStudy.CreatedByRefId = this.UserRefId;
caseStudy.CreatedTime = DateTime.Now;
}
caseStudy.LastModifiedByRefId = this.UserRefId;
caseStudy.LastModifiedTime = DateTime.Now;
if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
{
caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
}
caseStudy.ApprovedByRefId = null;
caseStudy.ApprovedTime = null;
this.Entities.SaveChanges();
var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
.Select(m => m.AdditionalMaterialRefId)
.ToArray();
var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
.Where(m =>
m.CaseStudyRefId == caseStudy.CaseStudyRefId &&
!existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
.ToArray();
foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
{
this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
}
this.Entities.SaveChanges();
}
In general it is what you have to do. 通常,这是您必须要做的。 You must tell EF about each change you want to perform when attaching detached object graph.
附加分离的对象图时,必须将要执行的每个更改告知EF。 I don't say that your code cannot be simplified but you will still have to deal with every entity and setting its state if you want it to be added or modified.
我并不是说您的代码无法简化,但是如果您要添加或修改它,您仍然必须处理每个实体并设置其状态。
Here is little bit older but still valid answer about the topic - in short nothing has changes since I wrote it, only new DbContext API was created which still sits on top of the old API. 这是关于该主题的较旧但仍然有效的答案-简而言之,自从我编写它以来,没有任何变化,仅创建了新的DbContext API,该API仍位于旧API的顶部。 The best description of this topic I have seen so far is in book Programming Entity Framework: DbContext .
到目前为止,我对这个主题的最佳描述是在《 编程实体框架:DbContext》一书中 。
How about just doing: 怎么做:
db.CaseStudies.Attach(caseStudy);
db.Entry(caseStudy).State = EntityState.Modified;
db.SaveChange();
That will save all changes in your model to the db. 这会将模型中的所有更改保存到数据库。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.