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

时间:2015-05-29 06:00:35

标签: c# entity-framework ef-code-first

我有实体与儿童实体的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; }
}

使用以下映射...

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Child>()
        .HasRequired(x => x.Parent)
        .WithMany(x => x.Children)
        .HasForeignKey(x => x.ParentId)
        .WillCascadeOnDelete(true);
}

查看生成的数据库,确实将外键关系标记为删除时级联。所以数据库架构看起来很好。抛出错误的实际代码......

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

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

你的代码匹配得很好,所以我认为你正确配置了它:https://msdn.microsoft.com/en-us/data/jj591620.aspx#CascadeDelete

我不知道为什么这不起作用,cascade一直对我有用。我怀疑有些配置。我总是禁用延迟加载,代理生成和验证,这样可以看一下。

以下是一些尝试:

1)您是否可以从数据库中手动删除该项目并进行级联工作?

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

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

ctx.Configuration.ValidateOnSaveEnabled = false;  

4)当你使用find时会加载子进程(如果在本地上下文中找到它可能会执行)或者是否启用了延迟加载。如果我没记错的话,设置状态是递归的,这可能会弄乱一些东西。您可以在changetracker中签入标记为删除的实体数量。

答案 1 :(得分:1)

您的错误是由Entity Framework生成的,而不是由您的数据库生成的。

问题是您使用的是context.Entry<Parent>(p).State = EntityState.Deleted而不是context.Parents.Remove(p)。主要区别在于,在父句柄上调用Remove,为具有加载到上下文中的必需关系的任何子项设置要删除的实体状态。 State = EntityState.Deleted没有。

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

最好使用DbSet.Remove

有关详细信息,请参阅此处:

Delete parent with children in one to many relationship