【问题标题】:EF Core is attempting to update a record that doesn't existEF Core 正在尝试更新不存在的记录
【发布时间】:2020-08-06 17:47:20
【问题描述】:

更新:在我创建这篇文章之后,我没有看到导致插入失败的代码。现在一切都按预期工作。很抱歉,感谢您花时间提供帮助。

我遇到了一个问题,即 EF 尝试更新不存在的记录。我需要插入记录。

示例代码如下:

DoStuff(List<ParentObj> listParent, List<OtherParent> listOtherParent)
{
    foreach(var op in otherParent)
    {
        var updateThisParentRecord = listParent.FirstOrDefault(x => x.Id == op.Id);
        if(updateThisParentRecord != null)
        {
            updateThisParentRecord.ChildRecordList.Add(new ChildRecord
            {
                //set relevant props not PK as it is an identity column
                OtherChildObject = new OtherChildObject 
                {
                    //set relevant props not PK as it is an identity column
                }
            });
        }
    }
    await _parentObjectContext.SaveChangesAsync();
}

型号代码:

public partial class ParentObj
{
    public ParentObj()
    {
        ChiledRecordList = new HashSet<ChildRecord>();
    }

    public int Id {get;set;}
    public virtual ICollection<ChildRecord> ChildRecordList {get;set;}
}

public partial class ChildRecord
{
    public int Id {get;set;}
    public int ParentId {get;set;}
    public int OtherChildObject {get;set;}

    public virtual OtherChildObject OtherChildObject {get;set;}
    public virtual ParentObj {get;set;}
}

public partial class OtherChildObject
{
    public OtherChildObj()
    {
        ParentObj = new HashSet<ParentObj>();
        ChildRecord = new Hashset<ChildRecord>();
    }

    public long Id {get;set;}
    //now that I have written this out, the below line seems strange and may 
    //be keyed wrong?
    public virtual ICollection<ParentObj> ParentObj {get;set;}
    public virtual ICollection<ChildRecord> ChildRecord {get;set;}
}

保存时抛出以下异常:

"数据库操作预计会影响 1 行,但实际上会影响 0 行。 自加载实体以来,数据可能已被修改或删除。 有关理解和处理乐观并发异常的信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=527962。”

这是异常条目列表中的内容:{{Id: 1000} Modified EntityType: ChildRecord}

EF 生成的 SQL 正确地创建了 OtherChildObject,但它正在尝试更新不存在的 ChildRecord。有谁知道发生了什么?提前致谢

【问题讨论】:

  • 人们会想看你的模型代码
  • 已更新型号代码
  • 你在“//设置相关道具而不是PK,因为它是一个身份列”部分中实际设置了什么?
  • 我需要在此处添加更新。还有一些其他邪恶的代码从来没有线程通过它,它正在做一些愚蠢的事情,直到我意识到我一直跨过一个我认为之前已经被 QC 过的方法时我才注意到。

标签: c# .net-core entity-framework-core


【解决方案1】:

DetectChanges honors store-generated key values 的重大更改:

旧行为

在 EF Core 3.0 之前,DetectChanges 发现的未跟踪实体会 在已添加状态中被跟踪并在以下情况下作为新行插入 调用 SaveChanges。

新行为

从 EF Core 3.0 开始,如果实体使用生成的键值 并设置了一些键值,然后实体将在 修改状态。这意味着实体的一行被假定为 存在,并且会在调用 SaveChanges 时更新。如果钥匙 未设置值,或者如果实体类型未使用生成的键, 那么新实体仍将像之前一样被跟踪为已添加 版本。

为什么

进行此更改是为了使其更轻松、更一致地工作 使用商店生成的键时,实体图断开连接。

缓解措施

如果配置了实体类型,此更改可能会破坏应用程序 使用生成的键,但键值显式设置为新的 实例。解决方法是将关键属性显式配置为 不使用生成的值。例如,使用 fluent API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedNever();

或带有数据注释:

[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }

如果您明确设置 ChildObjects 的 Id 并且实体使用生成的键值,那么它们将在 Modified 状态下被跟踪。

【讨论】:

  • 每当我进行建议的更改时,我都会收到此错误:{“当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'ChildRecord' 中插入标识列的显式值。”}
  • 您对 PK 属性的初始配置是什么? [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 还是 .ValueGeneratedOnAdd()?
  • 在我最终独立尝试的原始模型构建器或实体上没有任何这些注释或方法都导致相同的错误。
  • 这似乎是一个难题,您希望生成 Id,但在您的示例中不允许这样做。唯一的解决方案是单独添加 ChildRecord,而不是通过 ParentRecord。
  • 这就是我开始前进的方向。它只是感觉肮脏和错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多