【问题标题】:Replace multi-level relationship in Entity Framework Core 6 vs 7替换 Entity Framework Core 6 与 7 中的多级关系
【发布时间】:2023-02-19 05:45:36
【问题描述】:

我有以下型号

public partial class Parent
{
    public int IdParent { get; set; }

    public virtual ICollection<FirstChild> FirstChild{ get; set; } = new List<FirstChild>();
}

public partial class FirstChild
{
    public int IdFirstChild { get; set; }

    public virtual ICollection<SecondChild> SecondChild { get; set; } = new List<SecondChild>();
}

public partial class SecondChild 
{
    public int IdSecondChild  { get; set; }

    public virtual ICollection<ThirdChild> ThirdChild{ get; set; } = new List<ThirdChild>();
}

public partial class ThirdChild
{
    public int IdThirdChild { get; set; }

    public String SomeProperty{ get; set; }
}

我用这种方式更新Parent所有它的关系:

var parentDB = _context.Parent.Single(x => x.IdParent == {id})
.Include(x => x.FirstChild)
.ThenInclude(x => x.SecondChild)
.ThenInclude(x => x.ThirdChild);

parentDb.FirstChild = {newCollectionValuesList}

_context.SaveChanges();

这适用于 EF Core 6:

  • 如果在{newCollectionValuesList} 中,parentDb.FirstChild 中已经存在一个元素(相同 ID),它会更新(及其所有层次结构)
  • 如果if不存在,会添加
  • 如果它存在但未在{newCollectionValuesList} 中指定,它将被删除

当我升级到 EF Core 7 时,我开始遇到这个错误:

无法跟踪实体类型“SecondChild”的实例,因为已跟踪具有键值“{IdSecondChild: XXXX}”的另一个实例。附加现有实体时,确保只附加一个具有给定键值的实体实例

我在查询中添加了 .AsNoTracking() 来解决这个问题,但是删除不起作用(当 {newCollectionValuesList} 不包含数据库中存在的元素时,不会被删除)

我不想手动遍历所有关系并手动添加条件来更新子元素

我在What's new in EF7Breaking changes in EF7 和之前的 SO 问题中都没有找到与此相关的任何内容

这是一个带有集成测试的sample project来重现问题

【问题讨论】:

  • 你能发一个 minimal reproducible example 因为当前代码甚至不应该编译。
  • 这更有可能是由于数据不同于 EF 版本。看起来 newCollectionValuesList 包含多个具有相同密钥的 SecondChild 实例,或者一个与已附加实例具有相同密钥的实例。
  • 完全一样的数据。我在集成测试中发现了这个错误(不是通过手动测试)。所以输入是完全一样的
  • 为什么这个例子不应该编译?
  • 我添加了一个示例项目来重现问题

标签: c# entity-framework-core


【解决方案1】:

我在 github 的 efcore 问题中得到了 this thread 的回复

这是为7.0.4 计划的错误。 在此之前,这是一个解决方法:

在从数据库中选择之前,从 EF 更改跟踪器中清除 FirstChild

var existingParent = _context.Parent.Local.FirstOrDefault(x => x.IdParent == parentUpdate.IdParent);
    existingParent?.FirstChild.Clear();
    _context.ChangeTracker.DetectChanges();

var parentDB = _context.Parent.Single(x => x.IdParent == {id})
    .Include(x => x.FirstChild)
    .ThenInclude(x => x.SecondChild)
    .ThenInclude(x => x.ThirdChild);

parentDb.FirstChild = {newCollectionValuesList}


_context.SaveChanges();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多