我首先使用代码创建了一个sql服务器数据库。有两个表具有一对多的关系。该数据库可以正常工作,并且创建良好。
在sql server中,如果我尝试删除分类记录之一,则会收到错误消息(参照完整性限制)。这就是我希望它起作用的方式。但是在ef core中,如果我删除一个分类dbset.Remove(classification)
,则会删除该分类,并将客户中的分类设置为null
。
我认为这就是DeleteBehavior.ClientSetNull
的工作方式。
https://docs.microsoft.com/en-us/ef/core/saving/cascade-delete中有一个注释“ EF Core 2.0中的更改”,它说明了DeleteBehavior函数。
I have the next records:
Classification:
Id Name
1 General
2 Others
Customers:
Id Name IdClassification
1 Customer A 1
2 Customer B 2
3 Customer C <null>
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
...
public int? IdClassification { get; set; }
public Classification Classification { get; set; }
}
public class Classification
{
public int Id { get; set; }
public string Name { get; set; }
...
public ICollection<Customer> Customers { get; set; }
}
public class Context : DbContext
{
public virtual DbSet<Classification> Classifications { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Classification>(
entity =>
{
entity.HasKey(e => e.Id);
});
modelBuilder.Entity<Customer>(
entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.IdClassification);
...
// Claves foráneas
entity.HasOne(c => c.Classification)
.WithMany(x => x.Customers)
.HasForeignKey(x => x.IdClassification)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_Customer_Classification");
});
}
}
是否有办法防止ef core中的分类记录删除? (我不想检查是否有任何与分类链接的客户记录,因为我必须将分类与更多表一起使用)。 预先感谢。
答案 0 :(得分:1)
EF Core 3.0为DeleteBehavior
枚举添加了几个新值-ClientCascade
,NoAction
,ClientNoAction
。不幸的是,文档没有更新(API参考中的枚举值除外),并且在3.0重大更改-DeleteBehavior.Restrict has cleaner semantics中仅提到了ClientNoAction
:
旧行为
在3.0之前,
DeleteBehavior.Restrict
使用Restrict
语义在数据库中创建了外键,但也以非显而易见的方式更改了内部修正。新行为
从3.0开始,
DeleteBehavior.Restrict
确保使用Restrict
语义创建外键,即没有级联;违反约束条件-不会影响EF内部修复。为什么
进行此更改是为了以直观的方式改善使用
DeleteBehavior
的体验,而没有意外的副作用。缓解措施
可以使用
DeleteBehavior.ClientNoAction
恢复以前的行为。
更多信息包含在相关的跟踪问题-12661: Update DeleteBehavior to be more consistent and understandable
中老实说,即使阅读完所有内容,我也觉得它不干净,但更加令人困惑。 Restrict
似乎已经过时,并被NoAction
取代,无论实际上怎么说,确实将已加载的相关实体的导航属性/ FK设置为null
,因此导致SET NULL
的数据库行为已经发生。
尝试了所有方法之后,唯一可以满足您期望的选项就是上述ClientNoAction:
注意:使用此值是不寻常的。考虑使用
ClientSetNull
来匹配禁用级联删除的EF6行为。对于
DbContext
跟踪的实体,当删除相关的主体实体时,从属实体中外键属性的值不会更改。这可能会导致实体图不一致,其中外键属性的值与图中的关系不匹配。如果数据库是使用Entity Framework Migrations或
EnsureCreated()
方法从模型创建的,那么如果违反了外键约束,则数据库中的行为将产生错误。
不管他们在一开始的音符如何。
话虽如此,只需将Restrict
替换为ClientNoAction
即可解决问题。不需要数据库迁移,因为此更改仅影响客户端行为。
答案 1 :(得分:0)
好吧,分类实体需要正确的初始化,假设要删除限制规则。
modelBuilder.Entity<Classification>()
.HasKey(e => e.Id)
.HasMany(e => e.Customers)
.WithOne(e => e.Classification)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(true);
希望这会有所帮助。