简介
本文介绍了如何在EF Core中配置级联删除,以解决删除Greenhouse时自动删除相关IotLog的需求。
通过在DbContext的OnModelCreating方法中配置实体关系,使用HasMany/WithOne定义一对多关系,并设置OnDelete(DeleteBehavior.Cascade)启用级联删除。
这样当删除温室时,所有关联该温室的日志会被自动删除,而GreenHouseId为NULL的日志不受影响,既满足了业务需求,又保持了数据完整性。
需求
我有多个表
Greenhouse、Device、User
在操作这些表的时候,会创建一些日志。
我将这些日志统一存储到一个IotLog表中。
IotLog 表结构
csharp
public class IotLog
{
[Key]
[StringLength(36)]
public string IotLogId { get; set; } = Guid.NewGuid().ToString();
[StringLength(36)]
public string? DeviceId { get; set; }
[StringLength(36)]
public string? UserId { get; set; }
[StringLength(36)]
public string? GreenHouseId { get; set; }
//中间省略
[JsonIgnore]
public virtual Greenhouse? Greenhouse { get; set; } = null!;
}
目标,删除Greenhouse、Device、User时,需要删除对应的日志。这就涉及到级联删除了。
以Greenhouse为例,
csharp
public class Greenhouse
{
[Key]
[StringLength(36)]
public string GreenhouseId { get; set; } = Guid.NewGuid().ToString();
//中间省略
[JsonIgnore]
public virtual ICollection<IotLog> IotLogs { get; set; } = new List<IotLog>();
}
目前在属性上,添加特性,已经无法做到了。因此,需要在 DbContext中进行更多配置
DbContext 修改
csharp
public class MySQLContext : DbContext
{
// 其他 DbSet 定义...
public DbSet<Greenhouse> Greenhouses { get; set; }
public DbSet<IotLog> IotLogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置 Greenhouse 与 IotLog 的一对多关系,并启用级联删除
modelBuilder.Entity<Greenhouse>()
.HasMany(g => g.IotLogs) // 一个温室关联多个日志
.WithOne(l => l.Greenhouse) // 一个日志关联一个温室
.HasForeignKey(l => l.GreenHouseId) // 外键字段
.OnDelete(DeleteBehavior.Cascade); // 关键:级联删除规则
// 其他实体配置...
}
}
说明
OnDelete(DeleteBehavior.Cascade) 会强制数据库生成 ON DELETE CASCADE 外键约束,无论 GreenHouseId 是否可空。当删除温室时:
- 所有 GreenHouseId 等于该温室 ID 的日志会被自动删除;
- GreenHouseId 为 NULL 的日志不受影响(符合业务需求)。
- 保持 IotLog 中 public string? GreenHouseId { get; set; } 不变,不影响业务场景。