[英]Entity Framework Core Update child entities problem
In my ASP.NET Core 2.2.在我的 ASP.NET Core 2.2 中。 MVC project I have a master-detail form that I use for editing a PARENT table that also has a list of child entities (stored in CHILD table).
MVC 项目我有一个主从表单,用于编辑一个 PARENT 表,该表也有一个子实体列表(存储在 CHILD 表中)。
When I save the modifications on the form I first save the changes to the parent entity and then run the following method to update the corresponding child entities:当我在表单上保存修改时,我首先将更改保存到父实体,然后运行以下方法来更新相应的子实体:
private void UpdateChildList(ParentModel model)
{
// lists
var listOld = _parents.Get(model.IdParent).ListChilds;
var listNew = model.ListChilds;
var listNewInt = from x in listNew select x.IdChild;
// 1. remove deleted
var deleteList = new List<int>();
deleteList = listOld.Where(t => !listNewInt.Contains(t.IdChild)).Select(x => x.IdChild).ToList();
foreach (var d in deleteList)
{
var item = listOld.Where(x => x.IdChild == l).First();
_parents.DeleteChild(item);
}
// 2. update existing
var list = from x in listNew
where x.IdChild > 0
select x;
foreach (var item in list)
{
_parents.UpdateChild(item);
}
// 3. add new
list = from x in listNew
where x.IdChild == 0
select x;
foreach (var item in list)
{
_parents.AddChild(item);
}
}
1. deleting works OK & 3. adding works OK, but 2. UPDATING produces the following error: 1.删除作品 OK & 3.添加作品 OK,但是2. UPDATING 产生以下错误:
InvalidOperationException: The instance of entity type 'Child' cannot be tracked because another instance with the same key value for {'IdChild'} is already being tracked.
InvalidOperationException:无法跟踪实体类型“Child”的实例,因为已经在跟踪具有相同键值 {'IdChild'} 的另一个实例。 When attaching existing entities, ensure that only one entity instance with a given key value is attached.
附加现有实体时,请确保仅附加一个具有给定键值的实体实例。 Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。
Note: I'm using service.AddScoped
to add services in my Startup class.注意:我正在使用
service.AddScoped
在我的 Startup class 中添加服务。
EDIT: I'm adding the code from my HTTPPost (in controller):编辑:我正在从我的 HTTPPost(在控制器中)添加代码:
[HttpPost]
public IActionResult Edit(ParentModel model)
{
// valid check
if (!ModelState.IsValid)
{
/// ... some lists for dropdowns here
return View(model);
}
var item = _parents.Get(model.IdParent);
item.Field1 = model.Field1;
// ... and other fields
// update parent
_parents.Update(item);
// update Child list
UpdateChildList(model);
return RedirectToAction("Index");
}
EDIT2: adding my code for delete/update/add child records EDIT2:添加我的删除/更新/添加子记录的代码
public void AddChild(Child item)
{
_dbContext.Add(item);
_dbContext.SaveChanges();
}
public void UpdateChild(Child item)
{
_dbContext.Update(item);
_dbContext.SaveChanges();
}
public void DeleteChild(Child item)
{
_dbContext.Remove(item);
_dbContext.SaveChanges();
}
When you do:当你这样做时:
var listOld = _parents.Get(model.IdParent).ListChilds;
Entity Framework retrieves information from the context and begin tracking this entities and when you do:实体框架从上下文中检索信息并开始跟踪这些实体,当您这样做时:
_parents.UpdateChild(item);
you invoke:你调用:
_dbContext.Update(item);
Which on other side tries to attaches this entity to a context again and sets its EntityState
to Modified
and so you get an exception.在另一边尝试再次将此实体附加到上下文并将其
EntityState
设置为已Modified
,因此您会遇到异常。
When you retrieve information from the database and then work with it, you are in the so called "Connected scenario" and Entity Framework context track all retrieved entities.当您从数据库中检索信息然后使用它时,您处于所谓的“连接场景”中,并且实体框架上下文跟踪所有检索到的实体。 As soon as you modify some data of this entities, the context sets its
EntityState
to Modified
because of modification is performed.一旦您修改了此实体的某些数据,上下文就会将其
EntityState
设置为Modified
,因为执行了修改。 So, then you can call the SaveChanges()
method, it builds and executes Update statement in the database.因此,您可以调用
SaveChanges()
方法,它在数据库中构建并执行 Update 语句。
So you have two options:所以你有两个选择:
Add .AsNoTracking()
in your retrieval query so you will do a no tracking queries and no entities will be added to the db context respectively.在您的检索查询中添加
.AsNoTracking()
以便您将执行无跟踪查询,并且不会将实体分别添加到数据库上下文中。 Then you will work in "Disconnected scenario" and you can use db context Update()
method;然后您将在“断开连接的场景”中工作,您可以使用 db context
Update()
方法;
Change the UpdateChild
method by mapping field by field so changing a field in the entity will set it's EntityState
to Modified
.通过逐个字段映射来更改
UpdateChild
方法,因此更改实体中的字段会将其EntityState
设置为Modified
。 Then remove _dbContext.Update(item)
at all because SaveChanges()
will do the entire work.然后完全删除
_dbContext.Update(item)
因为SaveChanges()
将完成整个工作。
Another thing to mention - doing a SaveChanges()
in a loop is generally not a good idea.另一件要提的事情 - 在循环中执行
SaveChanges()
通常不是一个好主意。 This mean that you send (n) queries to database, where (n) is the number of the records.这意味着您向数据库发送 (n) 个查询,其中 (n) 是记录数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.