实体框架:级联删除的工作方式与预期相反

时间:2016-04-05 14:14:25

标签: c# entity-framework-6

我有3个实体:AddressStudentFaculty。这是关系图:

enter image description here

实体类:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Faculty
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string Street { get; set; }
    public Student Student { get; set; }
    public Faculty Faculty { get; set; }
}

在我的Context文件中,我正在定义关系并将级联删除设置为true:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    modelBuilder.Entity<Student>()
        .HasRequired(s => s.Address)
        .WithOptional(a => a.Student)
        .WillCascadeOnDelete(true);

    modelBuilder.Entity<Faculty>()
        .HasRequired(s => s.Address)
        .WithOptional(a => a.Faculty)
        .WillCascadeOnDelete(true);
}

我的用例是,当我删除StudentFaculty对象时,我希望同时删除关联的Address。但是,它以其他方式工作。

对此有何想法/建议?

4 个答案:

答案 0 :(得分:2)

真正的问题是你没有正确地模仿你正在寻找的东西。您的学生和教师表之间没有语义差异。因此,假设迁移外键就足够了,你在关系上是不正确的。换句话说,主详细信息表中的主服务器是地址。您的模型显示地址和教师之间存在一对多关系,地址和学生之间存在一对多关系。因此,级联删除工作的唯一方法是首先删除地址。实际上,我可能会将类型添加为子表,以便一个人可以拥有多个地址的多个角色。

我会以不同的方式对其进行建模。我会说PERSON(ID,NAME,TYPE)=&gt; 0,1 ADDRESS(ID,STREET)。在这种情况下,如果您删除某个人(可以是教师或学生),相应的地址也将被删除。

这巧妙地证明了OO和Relational之间的脱节。采用纯OO方法进行数据存储可能会有点奇怪。

答案 1 :(得分:2)

在逻辑上,在什么时候,你想要一个没有人关联的地址吗?你不会。您想为某个人允许多个地址吗?如果没有,那么将所有这些字段打到同一个表中并完成 - 这基本上就是你所说的:你必须同时拥有一个人和一个地址,所以如果你不打算将它们分开,为什么要分开它们?允许多个,或b)允许零?在这种情况下,将它们放在同一个表中是第三范式,并且适用于大多数用途。

答案 2 :(得分:1)

正确的答案是将所有地址列移动到Student / Faculty表中。

然后,为了让EF对您的对象模型感到满意,可以使用Address类的ComplexType属性。

https://msdn.microsoft.com/en-us/data/jj591583.aspx?f=255&MSPPError=-2147217396

我说这是“正确答案”的部分原因&#34;是你还没有解决两个学生共享同一地址记录的问题。您的对象模型中没有任何内容阻止它发生,如果它发生了,那么当您尝试删除一个学生时会发生什么?

答案 3 :(得分:0)

如果您不想更改表架构,则有两种选择:

  1. 仅通过存储过程执行删除操作。由于这是存储逻辑,而不是业务逻辑,因此将删除规则封装在过程中是有意义的。

  2. 使用ON DELETE触发器。我个人不喜欢以这种方式使用触发器,但这是一种可能性,并允许你继续使用EF不变。