EF Code First:具有多个多对一关系的实体类型

EF Code First: Entity type with multiple many-to-one relationships

考虑 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)
*/

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


方法二:

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 那样优先考虑 code/model 简单性而不是数据库设计?或者我应该像方法 2 那样在考虑数据库设计的情况下编写 类?

Yes you do have to worry about the database schema,

在你的例子中可能不是特别明显,但在使用继承时尤其如此。

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

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

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

最常用的三种继承方法。

  • TPH Table 每个层级:一个大 table 用于所有派生的 class 人,具有教师的所有属性和学生合一 table
  • TPT Table 每种类型:教师/学生/个人在单独的 table 中。教师和学生有他们的个人数据的外键
  • TPC Table 每个具体 class:教师 table 包含教师和人员属性的所有数据以及学生 table,其中包含学生和人员属性的所有数据。

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

但是如果有很多学生属性是教师没有的,那么table就会有很多教师的空值。如果与学生人数相比没有很多老师,这可能不是问题,否则 space 的浪费可能是一个需要考虑的项目。

另一件需要考虑的事情是方案更改的频率。如果您真的确定教师永远是人,并且学生和教师之间的共同属性(= 人属性)将永远是共同的,那么 TPH 可能会更好:三个 tables:人/教师/ 同学们。

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

如果不在意scheme,你会发现Entity Framework会选择TPH:一大tablewith all students and teachers with all students and teachers with all properties of students and teachers

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

很容易做到这一点

如何做到这一点在 Inheritance Strategy in Code-First

中有很好的描述

顺便说一句,完整的文章对我开始使用 EF 编程非常有帮助 - code first