如何使用 Fluent API 正确控制 EF Core 中的级联删除?

How to properly control cascading deletion in EF Core using Fluent API?

我有两个实体,TagMember。一个成员可以标记多个标签。一个标签可以用来标记多个成员。这是一个明显的多对多关系案例,因为我使用的是 EF Core,所以我必须声明一个显式连接器,我称之为 Tag_Member。我是这样配置的

private void OnModelCreating(EntityTypeBuilder<Tag_Member> entity)
{
  entity.HasKey(e => new { e.TagId, e.MemberId });
  entity.HasOne(e => e.Tag);
  entity.HasOne(e => e.Member)
    .WithMany(e => e.Tag_Member)
    .HasForeignKey(e => e.MemberId);
}

删除时我希望强制执行的行为如下。

我对两点感到困惑。当我添加如下所示的删除条件时,我有很多选项可供选择,尽管阅读了 intellisense,但我不确定要使用哪个来强制执行上述行为。

entity.HasOne(e => e.Member)
  .WithMany(e => e.Tag_Member)
  .HasForeignKey(e => e.MemberId)
  .OnDelete(DeleteBehavior.NoAction);

我应该使用 NoActionClientNoActionRestrict 还是其他?我什至不清楚删除行为影响了哪些实体。是哪个?

第二个困惑点是我没有为标签配置显示 OnDelete()。我没有使用 WithMany() 因为该实体缺少对互连实体的引用。我仍然可以管理它的删除行为吗?我是否需要显式声明它才能实现请求的行为?

entity.HasOne(e => e.Tag)
  .OnDelete(DeleteBehavior.NoAction);

类大致是这样的。

public class Tag { public Guid Id { get; set; } }
public class Member { public Guid Id { get; set; } }

public class Tag_Member
{
  public Guid TagId { get; set; }
  public Guid MemberId { get; set; }
  public Tag Tag { get; set; }
  public Member Member { get; set; }
}

我的参考主要是this and this.

编辑:根据回答中的建议,成员与标签关系的最终版本。

private static void OnModelCreating(EntityTypeBuilder<Member> entity)
{
  entity.HasKey(e => e.Id); ...
}

private static void OnModelCreating(EntityTypeBuilder<Tag> entity)
{
  entity.HasKey(e => e.Id); ...
}

private static void OnModelCreating(EntityTypeBuilder<Member_Tag> entity)
{
  entity.HasKey(e => new { e.MemberId, e.TagId });
  entity.HasOne(e => e.Member).WithMany().OnDelete(DeleteBehavior.NoAction);
  entity.HasOne(e => e.Tag).WithMany().OnDelete(DeleteBehavior.NoAction);
}

I'm not even clear on which of hte entities that the deletetion behavior affects. Which is it?

这很简单。级联删除总是影响 dependent 实体(即包含 FK 的实体)。

I don't feel certain which to use to enforce the above behavior. Should I use NoAction, ClientNoAction, Restrict or someting else?

您似乎在使用 EF Core 3.0 预览版,它添加了更多尚未记录的选项。但是在数据库级别实现的 classic 级联删除的选项一直是 Cascade.

I haven't used WithMany() because that entity lacks references back to the interlinking entity.

为了能够流畅地配置关系方面,您必须使用 Has + With 对来完全指定关系方。由于 导航属性 对于关系的任何一方都不是强制性的,因此您只需要它来将正确的参数传递给 Has / With 方法 - 如果您有导航 属性,传递名称或 lambda 表达式访问器,否则不传递任何内容(但仍包括调用)。例如

entity.HasOne(e => e.Tag)
    .WithMany() // <--
    .OnDelete(DeleteBehavior.Cascade); // now you can do this

但请注意,对于 必需的 关系,DeleteBehavior.Cascade 默认 (换句话说,当 FK 不可为空时类型),因此您通常不需要为此进行流畅的配置。如果 属性 名称遵循 EF Core 命名约定,则根本不需要流畅的配置。

简单例子可见here.