【问题标题】:EF Code First: Entity type with multiple many-to-one relationshipsEF Code First:具有多个多对一关系的实体类型
【发布时间】:2016-03-14 18:55:39
【问题描述】:

考虑 3 个类:PersonCompanyFile

PersonCompany 完全不同且不相关,但它们各自都有一个 File 对象的集合。不管它属于哪个实体,File 始终具有相同的结构。

这个问题是关于如何最好地模拟File 可以拥有的多个多对一关系;在这种情况下,File 可以与PersonCompany 具有多对一关系(但不能在同一个实例中)。


方法一:

class Person
{
    public int Id {get;set;}
    public ICollection<File> Files {get;set;}
}
class Company
{
    public int Id {get;set;}
    public ICollection<File> Files {get;set;}
}
class File
{
    public int Id {get;set;}
    public string Path {get;set;}
}

/* 
    EF Generates:
    -----------------
    Table: Person (Id)
    Table: Company (Id)
    Table: File (Id, Path, Person_Id, Company_Id)
*/

从代码优先的角度来看,这似乎是最简单和最直接的,也是我最喜欢的。问题在于表File,它具有Person_Id 和Company_Id 可以为空的字段。从 DB 设计的角度来看,这似乎是错误的,因为这两个字段中只有一个具有值,而另一个始终为空。添加更多带有文件集合的类会使问题更加严重。


方法2:

class Person
{
    public int Id {get;set;}
    public ICollection<PersonFile> Files {get;set;}
}
class Company
{
    public int Id {get;set;}
    public ICollection<CompanyFile> Files {get;set;}
}
class File
{
    public int Id {get;set;}
    public string Path {get;set;}
}
class PersonFile
{
    public Person Person {get;set;}
    public File File {get;set;}
}
class CompanyFile
{
    public Company Company {get;set;}
    public File File {get;set;}
}

/*
    EF Generates:
    ------------------
    Table: Person (Id)
    Table: Company (Id)
    Table: File (Id, Path)
    Table: PersonFile (Person_Id, File_Id)
    Table: CompanyFile (Company_Id, File_Id)
*/

这完成了与方法 1 相同的事情,并且更接近于我在 DB 优先设计中的传统做法。但它需要两个我真的不需要的额外课程......或者我需要吗?我想这就是这个问题的重点......


在设计 Code First Entity Framework 应用程序时,我是否需要担心数据库架构?我可以像方法 1 中那样优先考虑我的代码/模型简单性而不是数据库设计吗?或者我应该像方法 2 那样在编写类时考虑到数据库设计?

【问题讨论】:

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


    【解决方案1】:

    是的,您确实需要担心数据库架构,

    在您的示例中可能没有具体说明,但在使用继承时尤其如此。

    这是因为关系数据库(尤其是 SQL)不知道继承的概念。在设计您的日程安排时,您必须决定哪种方法适合您的需求。

    例如,在创建学校数据库时,您可能会设计一个 Person,他有姓名、地​​址、电话号码等。

    您会发现学生和教师都有姓名、地​​址等。与普遍的看法相反,您会发现学生和教师都是人。

    最常用的三种继承方法。

    • TPH 每个层次结构的表:一张大表用于 Person 的所有派生类,在一张表中包含教师和学生的所有属性
    • TPT 每种类型的表格:教师/学生/人员位于单独的表格中。教师和学生的个人数据都有一个外键
    • TPC 每个具体类的表:包含教师和人员属性的所有数据的教师表和包含学生和人员属性的所有数据的学生表。

    您将使用哪个取决于共享属性的比例以及学生和教师之间的差异。如果它们几乎所有的属性都相同,那么一张桌子的 TPH 就足够了。

    但是,如果有很多教师没有的学生属性,那么该表将有很多教师的空值。如果与学生人数相比,教师人数不多,这可能不是问题,否则可能需要考虑空间浪费。

    要考虑的另一件事是方案多久更改一次。如果您确实确定教师将始终是 Persons,并且 Student 和 Teachers 之间的公共属性(= Person 属性)将始终是公共的,那么 TPH 可能会更好:三个表:Persons / Teachers / Students。

    另一方面,如果您认为无论何时需要学生,都需要他的个人数据,那么 TPH 将始终导致加入。也许在这种情况下,TPC 可能是更好的选择。但是,如果您经常只需要 Student 的特定数据而没有他的 Person 数据,那么 TPC 可能不是一个好的选择

    如果你不关心这个方案,你会发现 Entity Framework 会选择 TPH:一张包含所有学生和教师的大表,包含学生和教师的所有属性。

    如果您不想这样做,则必须告诉 EF 您需要其他方法之一。这可以使用 fluent API

    轻松完成

    如何做到这一点在Inheritance Strategy in Code-First中有很好的描述

    顺便说一句,整篇文章对我开始使用 EF 编程非常有帮助 - 代码优先

    【讨论】:

    • 谢谢!回复和链接都很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多