实体框架级联删除对于继承的类

时间:2016-01-02 12:15:31

标签: c# entity-framework cascading-deletes

显然,使用实体框架进行级联删除非常令人困惑。我发现了很多问题,但我找不到解决问题的方法。如果我手动设置“删除规则”以级联它都可以。但是通过Fluent API,我还没有找到在数据库中设置此属性的方法。

在我的情况下,我有一个基类(在数据库中有自己的表)

public abstract class PropertyBase
{
    public int PropertyID { get; set; }
    public string Name { get; set; }
    public virtual AspectBase AspectBase { get; set; }
}

我已经派生了存储Table Per Type的类。

public class TextProperty : PropertyBase
{
    public string Value { get; set; }
}

public class IntProperty : PropertyBase
{      
    public int Value { get; set; }
}

在我的数据库环境中,我有以下内容:

        modelBuilder.Entity<PropertyBase>()
            .ToTable("Properties")
            .HasKey(p => p.PropertyID);                

        modelBuilder.Entity<IntProperty>()
            .ToTable("IntProperties");

        modelBuilder.Entity<TextProperty>()
            .ToTable("TextProperties");

下面是“IntProperties”的数据库表的快照。 Keys of IntProperties

我需要在上图中设置所选外键的删除规则。如果我在数据库中手动执行此操作,那么一切正常。我真的不知道如何实现这一目标。请帮忙。

我知道它必须是WillCascadeOnDelete的东西,但是为了能够用Fluent API做到这一点我可能需要一些导航属性?

这不是一个重复的问题:因为在我的情况下,它是抽象基类的派生类。有人提到现有的数据库是不可能的,但幸运的是我没有现有的数据库。我正在尝试使用Fluent API完成此Code First。非常欢迎任何帮助!

2 个答案:

答案 0 :(得分:2)

这已经被更频繁地报道和讨论,例如:Cascade delete in entity framework ( table per type inheritance )。我认为这是重复的,但由于问题和Slauma的答案是关于EF版本4的,我认为现在是更新的时候了。

令人沮丧的是,虫子(我认为它)仍然存在。我可能会忽略一些边缘情况(我可能会这样做),但我认为在TPT中,base和subtype之间的关系可以默认为级联删除。

仍然会出现所提问题中指出的错误。在您的情况下,如果您删除拥有属性集合的主实体,您会看到它。我们假设你有这门课程:

class Master
{
    public int ID { get; set; }
    public virtual ICollection<PropertyBase> Properties { get; set; }
}

关联Properties被标记为级联删除。

现在,如果你这样做......

var master = context.Find(x);
context.Masters.Remove(master);
context.SaveChanges();

...您将看到EF DELETE发出一个Master语句。它依赖于数据库将删除级联到Properties表。嗯,确实如此,但是IntPropertyTextProperty的FK被违反了,因为这些级联删除。

您可以通过执行以下操作来解决此问题:

var master = context.Include(m => m.Properties).Single(m => m.ID == x);
context.Masters.Remove(master);
context.SaveChanges();

现在,EF明确删除了属性和子类型。 1

有趣的是,EF非常清楚地删除了一个属性,或者是......

var intProp = context.Properties.OfType<IntProp>().First();
context.Properties.Remove(intProp); // delete from the base table

......或......

var intProp = context.Properties.OfType<IntProp>().First();
context.IntProperties.Remove(intProp); // delete from the derived table

...它应该发出两个删除语句。

因此,您无需工具即可将TPT关联配置为级联。您必须手动将其添加到迁移脚本中。但是,这不会阻止EF对要删除的每个单独属性执行2个删除语句,因为它不知道数据库中的级联。这可能会导致严重的性能损失。但它将使您能够通过一个删除语句删除主记录(拥有属性)。

1 与EF 4相比,这似乎是一种改进,显然每个子记录都必须有Remove个语句。

答案 1 :(得分:0)

级联删除只能在数据库级别进行,EF在这方面不做任何事情。这里的问题是你(和许多其他人:P)混淆了使用 WillCascadeOnDelete 。它仅在您使用Code First开发流程时才有用,在这种情况下,EF将生成迁移代码以在数据库外键中设置此属性,仅此而已由数据库删除关系。

当您使用数据库第一个工作流程时,您的情况似乎就是这个设置。