在 EF 中更新父实体时如何添加/更新子实体 [英] How to add/update child entities when updating a parent entity in EF
问题描述
两个实体是一对多的关系(由code first fluent api构建).
The two entities are one-to-many relationship (built by code first fluent api).
public class Parent
{
public Parent()
{
this.Children = new List<Child>();
}
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
在我的 WebApi 控制器中,我有创建父实体(工作正常)和更新父实体(有问题)的操作.更新操作如下所示:
In my WebApi controller I have actions to create a parent entity(which is working fine) and update a parent entity(which has some problem). The update action looks like:
public void Update(UpdateParentModel model)
{
//what should be done here?
}
目前我有两个想法:
通过
model.Id
获取一个名为existing
的被跟踪的父实体,并将model
中的值一一赋值给该实体.这听起来很愚蠢.而在model.Children
中,我不知道哪个孩子是新的,哪个孩子被修改(甚至删除).
Get a tracked parent entity named
existing
bymodel.Id
, and assign values inmodel
one by one to the entity. This sounds stupid. And inmodel.Children
I don't know which child is new, which child is modified(or even deleted).
通过model
创建一个新的父实体,并将其附加到DbContext并保存.但是 DbContext 如何知道子节点的状态(新增/删除/修改)?
Create a new parent entity via model
, and attached it to the DbContext and save it. But how can the DbContext know the state of children (new add/delete/modified)?
实现此功能的正确方法是什么?
What's the correct way of implement this feature?
推荐答案
因为发布到 WebApi 控制器的模型与任何实体框架 (EF) 上下文分离,唯一的选择是加载对象图(父包括其子项)并比较哪些子项已被添加、删除或更新.(除非您在分离状态(在浏览器或其他任何地方)期间使用自己的跟踪机制跟踪更改,我认为这比以下更复杂.)它可能如下所示:
Because the model that gets posted to the WebApi controller is detached from any entity-framework (EF) context, the only option is to load the object graph (parent including its children) from the database and compare which children have been added, deleted or updated. (Unless you would track the changes with your own tracking mechanism during the detached state (in the browser or wherever) which in my opinion is more complex than the following.) It could look like this:
public void Update(UpdateParentModel model)
{
var existingParent = _dbContext.Parents
.Where(p => p.Id == model.Id)
.Include(p => p.Children)
.SingleOrDefault();
if (existingParent != null)
{
// Update parent
_dbContext.Entry(existingParent).CurrentValues.SetValues(model);
// Delete children
foreach (var existingChild in existingParent.Children.ToList())
{
if (!model.Children.Any(c => c.Id == existingChild.Id))
_dbContext.Children.Remove(existingChild);
}
// Update and Insert children
foreach (var childModel in model.Children)
{
var existingChild = existingParent.Children
.Where(c => c.Id == childModel.Id && c.Id != default(int))
.SingleOrDefault();
if (existingChild != null)
// Update child
_dbContext.Entry(existingChild).CurrentValues.SetValues(childModel);
else
{
// Insert child
var newChild = new Child
{
Data = childModel.Data,
//...
};
existingParent.Children.Add(newChild);
}
}
_dbContext.SaveChanges();
}
}
...CurrentValues.SetValues
可以接受任何对象,并根据属性名称将属性值映射到附加实体.如果模型中的属性名称与实体中的名称不同,则不能使用此方法,必须一一赋值.
...CurrentValues.SetValues
can take any object and maps property values to the attached entity based on the property name. If the property names in your model are different from the names in the entity you can't use this method and must assign the values one by one.
这篇关于在 EF 中更新父实体时如何添加/更新子实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!