EF代码优先设计:不同父类型/表上的通用集合类型

时间:2017-01-31 00:35:10

标签: entity-framework

我需要从Code-First角度使用Entity Framework 6.1.3来解决设计问题。

我们有名为"业务","人"和" PhoneNumbers"的表。企业可以拥有一对多的电话号码,而人可以拥有一对多的电话号码。我正在努力确定实现这一目标的最佳方法。我们已经探索了以下解决方案,但这两种解决方案都没有让我感到骄傲。解。你能提出建议吗?

  1. 使用公用电话表来保存商家和人员的号码。

    在此解决方案中,Phone表将具有到People表和Business表的RI。 ID字段可以为空,因此当它是商务电话时,参与者ID将为空,反之亦然:

    public Nullable<int> ParticipantID { get; set; }
    public Participant Participant { get; set; }
    
    public Nullable<int> BusinessID { get; set; }
    public Business Business { get; set; }
    
  2. 为Business(BusinessPhone)和Person(PersonPhone)电话号码创建单独的表。两个电话表都可以从原始电话表继承,但每个电话表都有相应的业务或人员的单独RI语句。这样,两个表都不需要可以为空的密钥。

  3. 例如,PersonPhone表格如下所示:

    public class PersonPhone : Phone
    {
        public int ParticipantID{ get; set; }
        public Participant Participant { get; set; }
    }
    

    这些解决方案中的任何一种是最佳实践吗?有更好的解决方案吗?您有什么推荐的吗?

3 个答案:

答案 0 :(得分:1)

我建议最好的选择是为此使用单独的表。使用名为PhoneNumber的公共ABC,并为每个集合父类型派生子类,每个类都映射到它们自己的表(TPC策略)。或者,将ABC映射到公共字段的公用表,并将参考表映射到人员或业务(TPT策略)的引用。

来自面向对象的背景,我们经常优化代码重用;继承是重用代码的策略;并且TPH是EF中继承结构的默认映射; 感觉将这两者都放在一个表中是正确的。但从DBA的角度来看,将这两个问题混为一谈就是滥用数据库中的数据结构。称之为“架构气味”。它可能会起作用,但是你放弃了很多数据库可以为你做的事情。你没有任何理由将自己画成一个角落。

有三种继承策略;这个EF教程网站has a good rundown。单表是TPH。通常我会使用它,即使它违反了第3范式,因为它简单且高效。如果类型因他们引用的其他类型而不同,那么非规范化妥协会带来收益递减。

我看到的主要问题是:有了一个表,你必须找到一种方法来混合单独的FK。使用一个列和一个鉴别器(甚至可能不合法使用EF)你失去了做的能力DRI和级联删除。使用两列时,您必须监视该列,并且在任何给定时间只有一列非空。无论使用哪种解决方案,您都将放弃存储空间。如果两个对象发生分歧 - 比如说,你必须向EmployeeName添加BusinessPhone - 这个问题只会加剧。

因此,在这种情况下,我建议在每个层次的表上使用每个类型的表或每个具体的表类型策略。

唯一剩下的一点就是三者都涉及妥协。我不会进行所有的权衡(你应该能够找到很多关于这些的讨论)。可能仍然存在TPH最有意义的情况,因为用例必须表现得非常好。

答案 1 :(得分:0)

我认为最好的方法是拥有一个名为'PhoneNumber'的表。 Business和People都可以有PhoneNumbers列表。

当然,如果PhoneNumber对于Business和People都是相同的,那么这是正确的。如果您想为人们的PhoneNumber添加额外的属性,我建议您使用第二个选项。

答案 2 :(得分:0)

拥有一个电话号码表似乎是更好的选择。你可以在PhoneNumbers实体上使用某种鉴别器来避免必须有两个可以为空的列吗?

所以你有一个PhoneNumber类,以及一个代表电话号码类型的可枚举。然后,您的企业和人员都有一个PhoneNumber列表,如您所述。示例 -

public class PhoneNumber
{   
    public int PhoneNumberId { get; set; }      
    public int PhoneNumber { get; set; }        
    public PhoneNumberType PhoneNumberType { get; set; }
    public Participant Participant { get; set; }
}

public enum PhoneNumberType
{
    Person,
    Business
}

This answer是一个非常相似的问题,如果你想看看它似乎是一个更好的选择。