小编典典

在 EF 中更新父实体时如何添加/更新子实体

all

这两个实体是一对多的关系(由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 控制器中,我有创建父实体(工作正常)和更新父实体(有一些问题)的操作。更新操作如下所示:

public void Update(UpdateParentModel model)
{
    //what should be done here?
}

目前我有两个想法:

  1. 获取一个名为existing的被跟踪父实体,并为该实体一一model.Id赋值。model这听起来很愚蠢。在model.Children我不知道哪个孩子是新的,哪个孩子被修改(甚至删除)。

  2. 通过 创建一个新的父实体model,并将其附加到 DbContext 并保存。但是 DbContext 怎么知道孩子的状态(新的添加/删除/修改)?

实现此功能的正确方法是什么?


阅读 78

收藏
2022-07-16

共1个答案

小编典典

因为发布到 WebApi 控制器的模型与任何实体框架 (EF)
上下文分离,所以唯一的选择是从数据库中加载对象图(父对象包括其子对象)并比较已添加、删除或更新。(除非您在分离状态(在浏览器或任何地方)期间使用自己的跟踪机制跟踪更改,在我看来这比以下更复杂。)它可能看起来像这样:

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可以采用任何对象并将属性值映射到基于属性名称的附加实体。如果模型中的属性名称与实体中的名称不同,则不能使用此方法,必须一一分配值。

2022-07-16