EF 默认是开户级联删除的,这此规则将会删除非空外键和多对多的关系,如果 在数据库上下文中的实体模型类 存在着 级联引用和多重删除路径,那么EF就抛出 级联引用和多重删除路径的异常。
Introducing FOREIGN KEY constraint 'FK_dbo.ReviewIndexSystem_dbo.Category_CategoryID' on table
'ReviewIndexSystem' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO
ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
如果一个实体类的一个属性类的名称为ID(Idid) 或为ClassNameID ,EF约定它就默认为是该类的主键。
如果一个实体类的一个属性名为 导航属性名+它的主键名,或简单的为 导航属性的类名的主键名,那么约定它为两实体间的外键。
如果主键、外键属性名字不满足以上规则,就可以通过 [Key]、[Foreingkey]来指定关系。
对一一对一或者一对多关系,要在依赖的实体上加上[ForeignKey]属性指明依赖,因为EF不知道哪是主要的哪是依赖的。
可能通过设置 外键值为空(string 类型外键默认为空。int等值类型的默认不为空,可以加?使之为空,比如int? PersonID 的外键)或者使用Fluent API来 关闭默认的级联删除规则。
1、可以在数据库上下文类的 覆写OnModelCreating()方法来 关闭整个全局的级联删除规则:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); //关闭一对多的级联删除。
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); //关闭多对多的级联删除。
2、可以在此方法中关闭个别实体间的级联删除规则:
//导航属性,用于FluentAPI来设置 删除EF 默认的级联删除规则。如果不配置级联删除,此模型将会导致循环或者多个删除路径。
modelBuilder.Entity<ReviewIndexItem>().HasRequired(indexItem => indexItem.Category).WithMany(cate => cate.ReviewIndexItems).WillCascadeOnDelete(false);
modelBuilder.Entity<ReviewIndexSystem>().HasRequired(indexSystem => indexSystem.Category).WithMany(cate => cate.ReviewIndexSystems).WillCascadeOnDelete(false);
modelBuilder.Entity<ReviewProject>().HasRequired(reviewProject => reviewProject.Category).WithMany(cate => cate.ReviewProjects).WillCascadeOnDelete(false);
在Code First 开发方式中,常作用数据注解和Fluent API 来配置实体间的关系。
1、如果使用[Requied]数据注解配置一个实体类的外键,则表明此类 仅指明了映射关系中对方不能为空,也包含了客户端的验证,和服务器端的验证。
public class A
{
[Required]
[Display(Name="评审项目类别")]
public string CategoryID { get; set; }
[Display(Name = "评审项目类别")]
public virtual Category Category { get; set; }
}
2、如果使用Fluent API来配置,则只添加实体间的关系,而不添加实体间的验证规则。
判断关系一方是否为0,取决于外键属性的类型,string 类型的外键默认可空,也就是说 是0或1 对*的关系,或者 01对1。
//假设我们关闭Requied 验证属性,使用FluentAPI来配置 1对多的关系。
modelBuilder.Entity<ReviewIndexUseItem>().HasRequired(useItem => useItem.ReviewIndexItem).WithMany(item => item.ReviewIndexUseItems);
modelBuilder.Entity<ReviewIndexUseItem>().HasRequired(useItem => useItem.ReviewIndexSystem).WithMany(system => system.ReviewIndexUseItems);
3、EF在调用SaveChanges()方法的时候 ,会报错误。
当EF调用 context.SaveChanges()方法的时候 ,会默认检查 所有改变实体的所有属性,一旦发现实体任何一个属性不能满足的验证规则,会抛出"一个或多个实体的验证失败请参阅“EntityValidationErrors”属性。"的异常。
第一种方式可以通过Fluent API来配置关系,而不添加验证规则,避免错误发生。
第二种方式是可以通过 在调用SaveChange()方法前临时关闭掉实体验证,验证,dbContext.Configuration.ValidateOnSaveEnabled = false; 关闭Savechanges的验证。)
所以使用[Required] 数据注解除了指定了实体间非空的关系,还带来了验证规则。容易引发saveChanges()时的验证错误。
使用[Requied] 来定义外键关系非空不是好方法,FlentAPI才是好办法。因为[Required]既指定了非空的外键关系,又添加了
模型非空的验证的规则。而后者只指定了实体间的关系。