更新相关模型而不最初找到父级但在更新时填充它

Updating a related model without finding the parent initially but populating it on update

我正在使用 ef-core 2.1 rc1,我有一个依赖模型,其中导航 属性 定义为复杂对象:

public class ChildModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ParentModel Parent { get; set; }
}

在一个视图中,我得到了 Id 和一个更新的 Name,我可以在不获取导航的情况下更新对象 属性,但是我想检索导航 属性 更新后。在以下情况下,即使调用了 Include,它也为空:

this.context.Update(childInstance);
await this.context.SaveChangesAsync();
Child child = await this.context.Children
    .Include(p => p.Parent)
    .SingleAsync(p => p.Id == childInstance.Id);

在这种情况下,在不知道父导航数据并在更新期间检索的情况下更新依赖模型的正确有效方法是什么?

问题是 childInstance 附加到上下文并被更改跟踪器认为是当前的影子 FK ParentId null,因此任何进一步的查询返回实体相同的 PK 将被忽略并简单地替换为该实例。

修复它的一种方法是在保存后分离实体实例:

await this.context.SaveChangesAsync();
this.context.Entry(childInstance).State = EntityState.Detached;

或从数据库重新加载:

await this.context.SaveChangesAsync();
await this.context.Entry(childInstance).ReloadAsync();

现在可以加载导航了属性:

await this.context.Entry(childInstance).Reference(c => c.Parent).LoadAsync();

但是一旦您需要在更新后从数据库中检索一些数据,可能更好的方法是通过首先从数据库加载实体实例然后应用更改来反转该过程。额外的好处是只有修改的属性将包含在 UPDATE 命令中(或根本不更新):

var dbChild = await this.context.Children
    .Include(p => p.Parent)
    .SingleAsync(p => p.Id == childInstance.Id);

// Update properties
dbChild.Name = childInstance.Name;
// ...

// Or more generically
this.context.Entry(dbChild).CurrentValues.SetValues(childInstance);

await this.context.SaveChangesAsync();