[英]DbContext.Save on parent with child objects throws “Conflicting changes detected”
[英]Creatng a new child with a relation to an existing parent creates a new parent at dbContext.save()
我有一個使用代碼優先實體框架模型創建的一對多父子關系。
下面的代碼創建了一個引用現有父代的新子代的結果是,我最終得到了一個新的父代條目。
我已經看到了建議的解決方案,即將父級附加到上下文或更改其EntityState。 但是我不認為這可行,因為這兩種模型存在於不同的上下文中。
在我看來,不同的上下文總是很奇怪,但是我讀到某個地方通常這樣做是為了使每個模型保持模塊化。 (即使它們使用相同的連接字符串ect)
因此,問題是:如何確保子級與現有父級關聯,而不與新創建的父級關聯?
即使不同的dbContext沒有引起問題,這是否明智?
我的控制器代碼:
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create([Bind(Include = "Information_Id,Information_Title,Information_LinkText,Information_URLBody")] Information information, int InformationContainer_Id)
{
InformationContainerDBContext dbContainer = new InformationContainerDBContext();
//information.Information_Container = (from p in dbContainer.InformationContainers where p.InformationContainer_Id == InformationContainer_Id select p).ToList()[0];
information.Information_Container = dbContainer.InformationContainers.Single(o => o.InformationContainer_Id == InformationContainer_Id);
if (ModelState.IsValid)
{
dbContainer.Entry(information.Information_Container).State = EntityState.Unchanged;
db.Informations.Add(information);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(information);
}
我的模特:
家長:
public class InformationContainer
{
[Key]
public int InformationContainer_Id { get; set; }
[Required]
public string InformationContainer_Title { get; set; }
[InverseProperty("Information_Container")]
public List<Information> Informations{ get; set; }
}
public class InformationContainerDBContext : DbContext
{
public InformationContainerDBContext()
: base(ConfigurationManager.ConnectionStrings["DataDBString"].ConnectionString)
{
}
public DbSet<InformationContainer> InformationContainers { get; set; }
}
兒童:
public class Information
{
[Key]
public int Information_Id { get; set; }
[Required]
public string Information_Title { get; set; }
[Required]
public string Information_LinkText { get; set; }
[Required]
[AllowHtml]
public string Information_URLBody { get; set; }
public InformationContainer Information_Container { get; set; }
}
public class InformationDBContext : DbContext
{
public InformationDBContext()
: base(ConfigurationManager.ConnectionStrings["DataDBString"].ConnectionString)
{
}
public DbSet<Information> Informations { get; set; }
}
我的觀點:
@model eCommSite.Areas.Admin.Models.Information
@{
ViewBag.Title = "Information Pages - Create";
}
<script type="text/javascript" src="~/Scripts/tinymce/tinymce.min.js"></script>
<script>tinymce.init({ selector: 'textarea' });</script>
<h2>Information Pages</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Create</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Information_Title, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Information_Title, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Information_Title, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Information_LinkText, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Information_LinkText, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Information_LinkText, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Information_Container, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<select name="InformationContainer_Id">
<option value="1">Help</option>
<option value="2">Company</option>
<option value="3">Information For Parents</option>
</select>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Information_URLBody, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10" style=" height:500px!important; width: 80%;">
<textarea id=" wysiwyg"
style=" height:350px; width: 500px;"
name="Information_URLBody"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
擺脫多余的DbContext,只有一個。 將此屬性添加到您的Information
類中,使其成為外鍵:
public int InformationContainer_Id { get; set; }
您的上下文應如下所示:
public class InformationDBContext : DbContext
{
public InformationDBContext()
: base(ConfigurationManager.ConnectionStrings["DataDBString"].ConnectionString)
{
}
public DbSet<Information> Informations { get; set; }
public DbSet<InformationContainer> InformationContainers { get; set; }
}
由於InformationContainer_Id
是外鍵,因此您的控制器代碼應該喜歡它並且應該可以工作。
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create([Bind(Include = "Information_Id,Information_Title,Information_LinkText,Information_URLBody")] Information information, int InformationContainer_Id)
{
if (ModelState.IsValid)
{
information.InformationContainer_Id = InformationContainer_Id;
db.Informations.Add(information);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(information);
}
您應該將代碼更改為:
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create([Bind(Include = "Information_Id,Information_Title,Information_LinkText,Information_URLBody")] Information information, int InformationContainer_Id)
{
if (ModelState.IsValid)
{
InformationContainerDBContext dbContainer = new InformationContainerDBContext();
var infContainer = dbContainer.InformationContainers.Single(o => o.InformationContainer_Id == InformationContainer_Id);
infContainer.Informations.Add(information);
dbContainer.SaveChanges();
return RedirectToAction("Index");
}
return View(information);
}
如果將導航屬性添加到已經存在的屬性的集合中,它將也添加到數據庫中。
這里發生了一些事情:
首先,擁有多個DbContext很生氣,通過一些工作,我將它們全部合並了。
(如果您正在閱讀這篇文章...。僅維護一個DbContext是巨大的,並且無論您多么擔心所涉及的可能工作,我都強烈建議合並,特別是如果您像我一樣只擁有多個上下文缺乏經驗。)
其次,我添加了來自另一個上下文的對實體的引用,並且還引用了實體(而不是其ID),這是在調用保存更改時創建的新實體
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.