【问题标题】:How to code (first) the following ternary relationship in MVC Entity Framework C# with fluent API?如何使用流畅的 API 在 MVC Entity Framework C# 中编写(首先)以下三元关系?
【发布时间】:2017-06-12 18:07:02
【问题描述】:

更新

看来我没有让自己明白。我可能错误地选择了问题。所以我会尝试另一个例子,希望能更好地说明我的问题。

新示例:犬种 - 疾病 - 药物。

说明

  • 一个犬种可能会受到多种疾病的影响。

  • 一种相同的疾病会影响多个犬种。

  • 一种药物对某种犬种的一种或多种疾病有效

  • 一种药物对治疗某种疾病的一只或多只狗有效

    • 因此,药物有一个必要的对列表,虽然每一对都应该是唯一的,但没有真正的关系键值,因为这两个值都可以重复。

代码

以下代码与 EF 一起正常工作,在 DogBreed 和 Disease 之间创建查找表,如下图所示:

[Table("dog_breed")]
public DogBreed (){
    public int ID { get;set; }
    public string DogBreedName { get;set; }
    public IList<Disease> Diseases { get; set; }
}

[Table("disease")]
public Disease (){
    public int ID { get;set; }
    public string DiseaseName { get;set; }
    public IList<DogBreed> DogBreeds { get; set; }
}

问题

我想知道如何将实体医学添加到我的项目中,并让 EF 生成下图所示的方案。

代码可能是这样的:

[Table("medicine")]
public Medicine (){
    public int ID { get;set; }
    public string MedicineName { get; set; }
    public Lookup<DogBreed,Disease> { get;set; }
}

但这不会产生想要的方案。我应该如何进行?

我想澄清一下,我的疑问是如何让代码在我的数据库上自动生成我想要的结构,这样我就可以无缝地使用实体框架功能,因此所有解决方案都意味着在数据库上手动创建表,或改变结构(即定义一个新类)已经被考虑过。我不是在寻找有关如何绕过该问题的建议。


旧解释

我有一个简单的三元关系,其中三个实体相关联,正如我在下面针对我的具体问题所弥补的示例中所描述的那样。问题是我不知道如何输入代码,以按照我的预期在我的数据库中获取表。

实体:学生、主题、教室。

  • 1 名学生有多个科目。
  • 1 个科目有多名学生参加。
  • 1 教室可以举办多个科目的课程,并与所有参加课程的学生相关,因此我们将有以下图表

因此,这可以很容易地在一个单独的表格中关联起来,该表格将以下三者关联起来,其中学生 1 将在教室 2 中学习主题 13 的课程。

这是我在以下方式编码时观察到的二元关系行为:

[Table("student")]
public class Student
{
[Key]
public int ID {get; set;}
public List<Subject> Subjects;
}

[Table("subject")]
public class Subject
{
[Key]
public int ID {get; set;}
public List<Student> Students;
}

在这种情况下,当我运行 Add-Migration 和 Update-Database 时,我会得到一个表 studentsubject,其中包含两个实体的 id 并自动关联多对多关系。

如果可能的话,如果关系中的类获得具有 3 个字段的中间表,那么编码类的方法是什么?。集合、属性、类字典...?

-我的示例的真正设计是在第一个列表中添加以下类:

[Table("classroom")]
public class Classroom
{
[Key]
public int ID {get; set;}
public KeyValuePair<Student, Subject> StudentSubject;
}
  • 数据库的任何其他配置都会获取重复数据。
  • 字典值不起作用(另外,它不正确,因为它与实体的真正含义不匹配,因为这三个之间在现实世界中没有真正的键值关系)
  • 在我的实际问题中,学生会有一个科目列表,一个科目有一个学生列表。然后,我将单独定义 Classroom,并通过学生主题的独特组合来识别。

暂时我将创建一个代表三元关系的类,虽然我觉得这不符合 KISS 原则。

  • 我在 windows 和 MySql Server 上使用 Entity Framework 6。

【问题讨论】:

  • 我认为这是多对多的关系。 EF Core 尚不支持此功能。您可以创建一个包含学生 ID 和学科 ID 的映射表。那会解决你的问题。您可以读取学生或主题的映射,然后使用该数据扁平化您的 api 模型。它有点工作,但它现在就是这样。
  • - 我使用的 EF 版本必须支持多对多关系,因为它确实会为二进制多对多关系自动创建您提到的表。 - 当你说你可以创建一个映射表时,你是什么意思。我的目的是尽可能少地手动创建,以避免错误并简化维护。在我的应用程序的这一点上,不需要展平。
  • 三元关系没有很好地规范化。如果教室发生变化,您必须更新 n 记录(n = 该学科/教室中的学生人数)。您可能应该使用 SubjectClassroom 实体以及该实体与 Student 之间的多对多关系。
  • @GertArnold,您能否扩展您的解释。关系如何没有很好地正常化?必须更新n 记录有什么问题?您可以立即使用外键更新中间表。我看不到 SubjectClassroom 实体如何使事情变得更容易。我更新了我的帖子,也看看那个例子,我觉得它更适合我的问题。问候。

标签: c# entity-framework database-design ef-code-first ef-fluent-api


【解决方案1】:

“Classroom”对象中不需要直接提及“Students”,因为它有一个“subjects”列表,而“subject”本身也有一个“Student”列表

这是错误的:

public KeyValuePair&lt;Student, Subject&gt; StudentSubject;

这意味着在“Subject”对象中插入Student到主题一次,在Classroom中插入一次“Again”,为什么?!

您必须拥有这样的东西,EF 才能做到这一点:

[Table("classroom")] public class Classroom { [Key] public int ID {get; set;} public List<Subject> Subject; }

这将是您每个教室的每个科目的学生

List<Student> classroomSubjectStudents = classroom.Subjects .Where(x=>x == someSubject) .Select(x=>x.Students).ToList();

【讨论】:

  • 这将为您提供一个学习数学或法语的学生列表,但如果您需要一个在 102 室学习数学与在 205 学习数学课的学生的列表,您需要 Gert 提到的连接表。
  • 如果一个主题可以有多个教室,那是对的,在这种情况下,我建议制作另一个主要对象,其中包含课程的属性,如主题、教师、有关时间的详细信息等。 . 我猜在现实世界中,这个新创建的对象每学期只会在课堂上接受
【解决方案2】:

找了一会儿,又等了一会儿,我回到学校:

根据定义,良好规范化的关系是二元关系。因此,示例中描述的三元关系不适用于 code first,但是关系的性质使得形成它的二元关系(狗品种 - 药物,药物 - 疾病,狗品种 - 疾病) 重要到足以独立形成实体。

根据您的问题,您应该只选择一个来形成一个实体。所以这个问题的答案是......

要首先利用实体框架和代码,为了编写三元关系,您必须使两个部分之间的关​​系成为实体本身。

[Table("dog_breed")]
public DogBreed (){
    public int ID { get; set; }
    public string DogBreedName { get; set; }
    public List<PairMedicineDisease> PairsMedicineDisease { get; set; }
}


[Table("medicine")]
public Medicine (){
    public int ID { get;set; }
    public string MedicineName { get;set; }
}

[Table("disease")]
public Disease (){
    public int ID { get;set; }
    public string DiseaseName { get;set; }
}

[Table("pair_medicine_disease")]
public PairMedicineDisease (){
    public int ID { get;set; }
    public Disease Disease { get;set; }
    public Medicine Medicine { get;set; }
}

感谢所有试图提供帮助的人,特别是@Gert Arnold,他们为我指明了正确的方向。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多