C# 代码首先拒绝级联删除实体

C# 代码首先拒绝级联删除实体,c#,entity-framework,ef-code-first,C#,Entity Framework,Ef Code First,我有一个父实体,与子实体有0对多关系。当我删除父对象时,我希望它自动级联删除所有附加的子对象。尝试这样做会导致以下异常 操作失败:无法更改关系,因为 一个或多个外键属性不可为空。当 对关系进行更改时,相关的外键属性为 设置为空值。如果外键不支持空值, 必须定义新关系,外键属性必须为 指定了另一个非空值,或者必须为不相关的对象 删除 我不理解有关设置空引用的消息。由于级联删除,子项将被删除,因此无需将任何子项设置为具有空引用 我的两个简单实体被定义为 public class Parent {

我有一个实体,与实体有0对多关系。当我删除父对象时,我希望它自动级联删除所有附加的子对象。尝试这样做会导致以下异常

操作失败:无法更改关系,因为 一个或多个外键属性不可为空。当 对关系进行更改时,相关的外键属性为 设置为空值。如果外键不支持空值, 必须定义新关系,外键属性必须为 指定了另一个非空值,或者必须为不相关的对象 删除

我不理解有关设置空引用的消息。由于级联删除,子项将被删除,因此无需将任何子项设置为具有空引用

我的两个简单实体被定义为

public class Parent
{
    [Key]
    public int Id { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    [Key]
    public int Id { get; set; }
    public int ParentId { get; set; }
    public virtual Parent Parent { get; set; }
}
公共类父类
{
[关键]
公共int Id{get;set;}
公共虚拟ICollection子项{get;set;}
}
公营儿童
{
[关键]
公共int Id{get;set;}
public int ParentId{get;set;}
公共虚拟父级{get;set;}
}
使用以下映射

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Child>()
        .HasRequired(x => x.Parent)
        .WithMany(x => x.Children)
        .HasForeignKey(x => x.ParentId)
        .WillCascadeOnDelete(true);
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.has必需(x=>x.Parent)
.有许多(x=>x个孩子)
.HasForeignKey(x=>x.ParentId)
.WillCascadeOnDelete(真);
}
查看生成的数据库,它确实将外键关系标记为“删除时级联”。因此,数据库模式看起来不错。引发错误的实际代码

Parent p = context.Parents.Find(id);
context.Entry<Parent>(p).State = System.Data.Entity.EntityState.Deleted;
context.SaveChanges();
Parent p=context.Parents.Find(id);
context.Entry(p).State=System.Data.Entity.EntityState.Deleted;
SaveChanges();

有什么想法吗?

您的代码很好地匹配了这一点,因此我认为您正确地配置了它:

我不知道为什么这样不行,到目前为止cascade一直在为我工作。我怀疑有一些配置。我总是禁用延迟加载、代理生成和验证,因此可能需要对此进行一些研究

以下是一些可以尝试的东西:

1) 您可以从数据库中手动删除该项,然后级联工作吗

2) 这是sql错误还是“应用程序”错误?我怀疑这是一个应用程序错误,EF验证以某种方式触发。如果它来自数据库,则异常应该是和SqlException。我通常使用Sql Profiler检查命令是否也被发送

3) 如果是应用程序错误,请尝试禁用EF的验证,看看会发生什么

ctx.Configuration.ValidateOnSaveEnabled = false;  

4) 当您使用find时,它是否加载子级(如果在本地上下文中找到它,则可能会这样做),或者是否启用了延迟加载。如果我没记错的话,设置状态是递归的,这可能会搞糟一些事情。您可以在changetracker中检查标记为删除的实体数

您的错误是由实体框架而不是数据库生成的

问题是您使用的是
context.Entry(p).State=EntityState.Deleted
而不是
context.Parents.Remove(p)
。主要区别在于,在父对象上调用
Remove
,可以将加载到上下文中具有所需关系的所有子对象的实体状态设置为deleted<代码>状态=实体状态。已删除的不会

在您的案例中,可能有一些相关的
实体加载到上下文中,EF正在抱怨孤儿。如果没有加载任何子级,DELETE语句将被发送到数据库,数据库将正常处理级联删除

最好使用
DbSet.Remove

有关更多详细信息,请参见此:


使用集合上的“删除”方法完成了此任务。谢谢