EF6和EF Core都支持级联删除。EF6要禁止级联删除是在数据库上下文的OnModelCreating方法中设置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//移除外键级联删除
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}
这个设置是对整个数据库的所有表起作用。
EF Core禁止级联删除只能对表的每一个外键进行设定(反正我在EF Core文档中没找到对整个数据库设置的方法)。
EF Core对删除父实体时可以执行三种操作:
1. 可以删除子项/依赖项
2. 子项的外键值可以设置为 null
3. 子项保持不变
第一种就是级联删除,即删除父项时自动删除相关的子项。
第二种是删除父项时,将子项对应的外键值设置为null,如果该字段不能为null,则抛出异常。
第三种就是约束了,因为删除父项而子项保持不变,这是违反数据库约束的,如果父项已经被引用,直接抛出异常。
这三种操作被定义为枚举DeleteBehavior中的四个枚举值:
行为名称 | 对内存中的依赖项/子项的影响 | 对数据库中的依赖项/子项的影响 |
---|---|---|
Cascade | 删除实体 | 删除实体 |
ClientSetNull | 外键属性设置为 null | 无 |
SetNull | 外键属性设置为 null | 外键属性设置为 null |
Restrict | 无 | 无 |
对内存中的影响是指加载到内存中的数据,对数据库的影响则是在调用了SaveChange()方法后产生。可以看到ClientSetNull和Restrict对数据库的影响是一样的,所以说四个枚举值,实际上只有三种操作。
EF Core在创建数据库时,会根据外键是否允许为null来设置删除行为。
如果外键不允许为null,删除行为设置为Cascade,此时删除父项会自动删除相关的所有子项。当调用SaveChange()方法时,这一规则也会同样应用到数据库。
如果外键允许为null,删除行为设置为ClientSetNull,对应到数据库就是Restrict,删除被引用的父项时,如果没有调用SaveChange()方法,不会有任何问题,但调用SaveChange()时会抛出异常。
在代码中设定删除行为,可以重写数据库上下文的OnModelCreating方法:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
//表只有一个外键
builder.Entity<Project>()
.HasOne(p => p.Agent)
.WithMany()
.OnDelete(DeleteBehavior.Restrict);
//表有多个外键
builder.Entity<Light>(b =>
{
b.HasOne(l => l.LedController).WithMany().OnDelete(DeleteBehavior.Restrict);
b.HasOne(l => l.ControllerArea).WithMany().OnDelete(DeleteBehavior.Restrict);
});
}
HasOne方法的参数指向表的主表,比如上面的代码中,Agent是主表,Project是子表。WithMany方法的参数也是lambad表达式,指向的是主表中的导航属性,这里我没有为Agent表添加导航属性,所以WithMany方法的参数为空。这两个方法实际上说明了Agent表和Project表是一对多的关系。最后的OnDelete方法的参数就是删除行为了,也就是我们上面说到的DeleteBehavior的枚举值之一。
网友评论