不完整的EF代码 - 首先级联删除多对多关系

时间:2014-04-30 21:26:27

标签: c# .net entity-framework ef-code-first entity-framework-6

我有一个PhoneNumber实体,我想在多个实体中引用它。例如,有许多 PhoneNumbers的Contact实体,以及一个 PhoneNumber的Business实体。

public class PhoneNumber
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Number { get; set; }
}

public class Contact
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
}

public class Business
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [ForeignKey("PhoneNumber")]
    public int PhoneNumberId { get; set; }
    public virtual PhoneNumber PhoneNumber { get; set; }        
}

我已设置ContactBusiness,以便他们拥有单向导航属性。此外,电话号码是可选的。我还为Contact设置了许多关系,以防止EF在添加迁移时添加Contact_Id列。映射如下(注意WithMany()使用,因为PhoneNumber没有导航属性返回Contact):

modelBuilder.Entity<Contact>().HasMany(r => r.PhoneNumbers).WithMany()
            .Map(x => x.MapLeftKey("ContactId").MapRightKey("PhoneId"));

当我添加一个包含多个电话号码的Contact时,它会被添加正常。有ContactPhoneNumbers表和ContactPhoneNumbers链接表的记录。

然而,我正在努力解决的问题是当我删除联系人时。 EF正确删除ContactPhoneNumbers链接表和Contact条目中的条目,但它不会删除PhoneNumbers表中的条目。我已经看到使用modelBuilder进行映射的示例,其中使用了WillCascadeOnDelete(true),但使用WithMany()时该选项不可用。

如何才能使这种类型的级联删除正常工作?这个设置有可能吗?或者我是否需要为每个实体(联系人和业务)设置单独的PhoneNumbers表来设置相应的PhoneNumber表使用FK的关系(例如,Contact_Id)?

我对EF很新,所以欢迎任何建议。我可能会完全错误。

编辑:这是相关的迁移代码......

CreateTable(
    "dbo.PhoneNumbers",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Number = c.String()
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.Contacts",
    c => new
        {
            Id = c.Int(nullable: false, identity: true)
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.ContactPhoneNumbers",
    c => new
        {
            ContactId = c.Int(nullable: false),
            PhoneId = c.Int(nullable: false),
        })
    .PrimaryKey(t => new { t.ContactId, t.PhoneId })
    .ForeignKey("dbo.Contacts", t => t.ContactId, cascadeDelete: true)
    .ForeignKey("dbo.PhoneNumbers", t => t.PhoneId, cascadeDelete: true)
    .Index(t => t.ContactId)
    .Index(t => t.PhoneId);

CreateTable(
    "dbo.Business",
    c => new
        {
            Id = c.Int(nullable: false),
            PhoneNumberId = c.Int(nullable: false)
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.PhoneNumbers", t => t.PhoneNumberId, cascadeDelete: true)
    .Index(t => t.Id)
    .Index(t => t.PhoneNumberId);

1 个答案:

答案 0 :(得分:2)

为了级联删除工作,要进行级联的记录必须将外键返回到要删除的记录。因此,在您的示例中,您删除了联系人记录。因为它们是从ContactPhoneNumber到Contact的外键,所以级联工作。由于从PhoneNumber到ContactPhoneNumber没有外键,(外键是另一种方式),级联不会继续。

这是因为您将关系定义为多对多。如果您考虑尝试按照您的意愿对模型执行级联删除,如果删除ContactPhoneNumber然后删除其关联的PhoneNumbers,现在可能有其他ContactPhoneNumbers没有有效的PhoneNumber(因为一个PhoneNumber可以有很多ContactPhoneNumbers)。现在需要删除这些,这个过程将继续。数据库不喜欢这种循环级联。

我不完全清楚为什么你需要多对多的关系,如果你真的需要它,你将无法在删除时执行级联。如果你能建立你的关系:

1联系人 - * ContactPhoneNumber 1- * PhoneNumber,然后您可以将级联配置为您想要的工作方式。