EF Core 删除对自身的引用而不删除

EF Core Remove Reference to Self without deleting

我有一个 class 将自己引用为 'equivalent versions' 的链;但是一旦设置,我就无法清除此引用。

public class Foo
{
   public int FooId { get; set; }
   public string Name { get; set; }
   public virtual Foo EquivalentFoo { get; set; }

   public static void RunFluent(ModelBuilder modelBuilder)
   {
     EntityTypeBuilder<Foo> entity = modelBuilder.Entity<Foo>();
     entity.HasKey(f => f.FooId);
     entity.HasOne(f => f.EquivalentFoo).WithMany().IsRequired(false);
   }
}

我的控制器具有以下更新端点:

[HttpPut("{id}")]
public async Task<IActionResult> PutFoo(int id, Foo foo)
{
    ...

    _context.Entry(foo).State = EntityState.Modified;

    if (foo.EquivalantFoo != null)
    {
        _context.Entry(foo.EquivalantFoo).State = EntityState.Unchanged;
    }

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        ...
    }

    return NoContent();
}

将新的 EquivalentFoo 添加到没有的 EquivalentFoo 或将其更改为新的 Foo 效果很好。

我正在努力解决的问题是用 EquivalentFoo = null 传递一个 foo。即使 EquivalentFoo 可以为 null,并且数据库可以使用 null 键,EF Core 生成的外键列也不会更新为显示 null。它甚至不会抛出错误,只是不会更新。

请注意,在这种情况下,我实际上并不想从数据库中删除任何这些 Foos。所有应该发生的是正在更新的 Foo 现在应该有一个空键引用任何 EquivalentFoos.

根据文档,将 State 设置为 Modified 应该也将所有属性(包括阴影)设置为已修改。

然而,正如您已经观察到的那样,具有空值的影子 FK 属性(以及相应的参考导航 属性 同时为空)似乎有特殊处理,特别是未标记为已被上述操作修改(如果你使用 Update 方法也是如此)。

因此您需要强制 EF Core 更新 FK 属性,方法是使用 Reference 方法返回的 ReferenceEntry 手动将其标记为已修改,例如

//...
var entry = _context.Entry(foo);
entry.State = EntityState.Modified;
entry.Reference(e => e.EquivalentFoo).IsModified = true; // <--
//...

注意“?”标记 ParentFooRefno,这将允许您添加空值

    public class Foo
    {
       [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
       public int FooId { get; set; }
       public string Name { get; set; }

       public int? ParentFooRefno { get; set; }
       
       [ForeignKey("ParentFooRefno ")]
       public virtual Foo EquivalentFoo { get; set; }
    
        
    }