来自 EF Core 文档:
按照惯例,级联删除将被设置为级联
关系和 ClientSetNull 用于可选关系。级联
表示依赖实体也被删除。 ClientSetNull 意味着
未加载到内存中的依赖实体将保留
未更改,必须手动删除,或更新为指向有效的
主体。对于加载到内存中的实体,EF Core
将尝试将外键属性设置为 null。
使用连接实体类型配置和 NuGet Microsoft.EntityFrameworkCore.SqlServer 使用 Cascade 的多对多示例:
internal class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId),
j =>
{
j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
j.HasKey(t => new { t.PostId, t.TagId });
});
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public DateTime PublicationDate { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=data-annotations%2Cfluent-api-simple-key%2Csimple-key#join-entity-type-configuration
如果您引入更多路径,您最终可能会使用Microsoft.EntityFrameworkCore.Tools 或类似命令在Update-Database 上获得以下异常。
Microsoft.Data.SqlClient.SqlException (0x80131904):介绍
表 '' 上的 FOREIGN KEY 约束 '' 可能会导致循环或多个
级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或
修改其他 FOREIGN KEY 约束。无法创建约束或
指数。查看以前的错误。
一种解决方案可能是简单地将DeleteBehavior.Restrict 添加到关系中,但是在删除父实体时会再次出现类似错误,除非您自己清除每个关系。
例子:
实体类型 '' 和 '' 之间的关联已被切断,但是
该关系要么被标记为必需,要么被隐含
需要,因为外键不可为空。如果
当需要关系时,应删除依赖/子实体
被切断,配置关系使用级联删除。
考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来
查看关键值
您可以通过指定 DeleteBehavior.ClientCascade 来解决此问题,这将允许 EF 对加载的实体执行级联删除。
internal class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId)
.OnDelete(DeleteBehavior.Cascade),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId)
.OnDelete(DeleteBehavior.ClientCascade),
j =>
{
j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
j.HasKey(t => new { t.PostId, t.TagId });
});
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public DateTime PublicationDate { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.deletebehavior?view=efcore-5.0