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; }
}
我有一个 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; }
}