EF Code First:具有多个多对一关系的实体类型
EF Code First: Entity type with multiple many-to-one relationships
考虑 3 类:Person
、Company
和 File
。
Person
和Company
完全不同,没有任何关系,但它们各自都有一个File
对象的集合。不管它属于什么实体,File
总是具有相同的结构。
这个问题是关于如何最好地模拟 File
可以拥有的多个多对一关系;在这种情况下,File
可以与 Person
或 Company
具有多对一关系(但不能在同一实例中)。
方法一:
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
考虑 3 类:Person
、Company
和 File
。
Person
和Company
完全不同,没有任何关系,但它们各自都有一个File
对象的集合。不管它属于什么实体,File
总是具有相同的结构。
这个问题是关于如何最好地模拟 File
可以拥有的多个多对一关系;在这种情况下,File
可以与 Person
或 Company
具有多对一关系(但不能在同一实例中)。
方法一:
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