EFCore:简单属性更新期间的实体关联错误

Posted

技术标签:

【中文标题】EFCore:简单属性更新期间的实体关联错误【英文标题】:EFCore: Entities association error during a simple property update 【发布时间】:2019-01-03 03:43:22 【问题描述】:

我想在我的控制器中设置一个 bool 属性并将其保存到数据库中。 EF 会抛出一个关于其他甚至没有被修改的属性的错误。

实体 'Us​​er' 和 'RequestDetail' 之间的关联与 key value 'System.InvalidOperationException: 之间的关联 具有键值“Id: 40”的实体“User”和“RequestDetail”具有 已被切断,但关系要么被标记为“必需”,要么被 隐式需要,因为外键不可为空。如果 当需要关系时,应删除依赖/子实体 被切断,然后设置关系以使用级联删除。

如果我用一个附加参数调用我的方法,它必须更改一个 RequestDetail 记录的 RequestSent 属性,这很好用。 但是在没有这个附加参数的情况下调用该方法,它必须在多个 RequestDetail 记录上更改此属性。这就是它引发错误的地方。我不修改与用户相关的任何内容。 如果它必须一次执行更多记录,则会引发此错误。即使我使用 FirstOrDefaults() 和立即 SaveChanges() 将 foreach 重写为一段时间,它也会在第二轮引发错误。

我的方法:

var head = await _ctx.RequestHeads.FirstOrDefaultAsync(x=>x.Id == d.Id);
if (!d.DetailId.HasValue) 
            var details = _ctx.RequestDetails.Include(x=>x.BuyerUser)
                            .Where(x=>x.RequestHeadId == head.Id); 
//not working, always throws an error if it has to modify more than one record
            await details.ForEachAsync(detail => 
                detail.RequestSent = true;
            );
         else 
            var detail = head.Details.FirstOrDefault(x=>x.Id == d.DetailId.Value); //works ok, always
            detail.RequestSent = true;
        
        await _ctx.SaveChangesAsync();

我的模型:

public class RequestHead

    [Key, MaxLength(15)]
    public string Id  get; set; 
    public DateTime CreateDate  get; set; 
    public int CreateUserId  get; set; 
    [ForeignKey("CreateUserId")]
    public User CreateUser  get; set; 

    public DateTime? AcceptDate  get; set; 
    public int? AcceptUserId  get; set; 
    [ForeignKey("AcceptUserId")]
    public User AcceptUser  get; set; 

    public DateTime? CloseDate  get; set; 
    public int? CloseUserId  get; set; 
    [ForeignKey("CloseUserId")]
    public User CloseUser  get; set;      
    public int? CloseReason  get; set;    
    public bool IsArchive  get; set; 

    [MaxLength(8)]
    public string OrganizationCode  get; set; 

    [ForeignKey("OrganizationCode")]
    public Organization Organization  get; set; 

    public virtual ICollection<RequestDetail> Details  get; set; 
    public virtual ICollection<RequestAttachment> Attachments  get; set; 


public class RequestDetail

    [Key]
    public int Id  get; set; 

    public string RequestHeadId  get; set; 

    [ForeignKey("RequestHeadId")]
    public RequestHead RequestHead  get; set; 

    [MaxLength(20)]
    public string ProductCode  get; set; 

    [ForeignKey("ProductCode")]
    public Product Product  get; set; 
    public string ProductName  get; set; 
    public bool NoProductCode  get; set; 
    public string Description  get; set; 
    public DateTime CreateDate  get; set; 
    public int CreateUserId  get; set; 
    [ForeignKey("CreateUserId")]
    public User CreateUser  get; set; 


    public DateTime? DelegateDate  get; set; 
    public int? DelegateUserId  get; set; 
    [ForeignKey("DelegateUserId")]
    public User DelegateUser  get; set; 


    public int? BuyerUserId  get; set; 
    [ForeignKey("BuyerUserId")]
    public User BuyerUser  get; set; 

    public bool RequestSent  get; set; 
    public virtual ICollection<RequestAttachment> Attachments  get; set; 


上下文:

modelBuilder.Entity<RequestHead>()
            .HasOne(r=>r.CreateUser)
            .WithOne().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<RequestHead>()
            .HasMany(r => r.Details)
            .WithOne(x=>x.RequestHead)
            .HasForeignKey(rd => rd.RequestHeadId);
modelBuilder.Entity<RequestDetail>()
            .HasOne(r=>r.CreateUser)
            .WithOne().OnDelete(DeleteBehavior.Restrict);

【问题讨论】:

不确定是否相关,但User 关系中的两个.WithOne() 看起来非常可疑。他们可能应该是.WithMany()。另一个区别是“非工作”查询包含.Include(x=&gt;x.BuyerUser) @IvanStoev Include(x=>x.BuyerUser) 只是一个测试,如果问题可能是导航属性未加载。 .WithOne() 但是,我确信这一定是我的上下文配置中的内容。谢谢! 嗯,大多数 EF 消息......令人困惑 :) 我可以忍受(他们有很多功能要做,所以我猜消息是最低优先级)。行为怎么样,我猜一对一的代码需要单个记录,所以当第二个具有相同 FK 的记录进入时,他们会感到困惑并决定删除该记录:) 只是一个猜测 - 实际代码相当复杂。 @IvanStoev 您介意将其发布为答案,以便我可以关闭此问题吗? 没有时间撰写一个好的答案。请随时发布自我答案。很高兴它有帮助,编码愉快。 【参考方案1】:

解决方案是将 RequestDetail用户关系从 WithOne() 更改为 WithMany()。尽管错误消息有些误导,但@IvanStoev 的可能解释如下:

我猜一对一的代码需要单个记录,所以当 相同FK的第二张唱片进来了,他们感到困惑并决定 记录被删除

【讨论】:

以上是关于EFCore:简单属性更新期间的实体关联错误的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate - 错误脱水属性值 - 更新实体

NHibernate - 错误脱水属性值 - 更新实体

无法更新标识列“索引”。 EF核心

实体框架不生成关联属性

SwiftUI 计算属性显示“在视图更新期间修改状态,这将导致未定义的行为。”错误

EF Core - 添加相关实体时出错