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

时间:2016-03-14 01:00:05

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

考虑3个课程:PersonCompanyFile

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

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

方法1:

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具有可归零的字段。从数据库设计的角度来看,这似乎是错误的,考虑到两个字段中只有一个将具有值,而另一个将始终为null。使用文件集添加更多类会进一步加剧这个问题。

方法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中那样?

1 个答案:

答案 0 :(得分:1)

  

是的,你必须担心数据库架构,

在您的示例中可能没有特别说明,尤其是在使用继承时。

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

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

你会发现学生和教师都有姓名,地址等。与流行的看法相反,你会发现学生和老师都是人。

最常用的是三种继承方法。

  • TPH 每个层次结构的表:所有派生类的一个大表,其中所有属性的教师和学生都在一个表中
  • TPT 每种类型的表格:教师/学生/人员在不同的表格中。教师和学生拥有个人数据的外键
  • TPC 每个Concrete类的表:一个Teacher表,其中包含Teachers和Person Properties的所有数据,以及一个Student表,其中包含Student和Person Properties的所有数据。

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

但是,如果教师没有很多学生宿舍,那么教师会有很多空值。如果没有很多教师与学生人数相比,这可能不是问题,否则浪费空间可能是一个需要考虑的事项。

另一件需要考虑的事情是该计划的变化频率。如果你真的确定教师永远是人,并且学生和教师之间的共同属性(=人物属性)总是很常见,那么TPH可能会更好:三个表:人/教师/学生。

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

如果您不关心该计划,您会发现实体框架将选择TPH:一个大表,所有学生和教师都拥有学生和教师的所有属性。

如果你不想要这个,你必须告诉EF你想要其他方法之一。这可以使用 fluent API

轻松完成

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

中描述得相当不错

顺便说一下,完整的文章对我开始使用EF代码开始编程很有帮助