【问题标题】:Entity Framework - Relationship confusion实体框架 - 关系混淆
【发布时间】:2014-11-27 03:41:11
【问题描述】:

我在理解 Entity Framework Code Firsts 关系创建时遇到问题,因为我更习惯于传统方式。

一对多关系对我来说似乎很清楚:孩子只需要一个 foreignKey ID 属性来指示他们属于哪个 Parent。

public class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Childs { get; set; }
}

public class Child
{
   public int Id { get; set; }

   public int ParentId { get; set; } 
   public virtual Parent Parent { get; set; }
}

现在,我不太确定如何正确创建 多对多 关系。可能需要一个额外的表ParentChild,所以不需要(外键)ID属性吧?

public class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Childs { get; set; }
}

public class Child
{
   public int Id { get; set; }
   public virtual ICollection<Parent> Parents { get; set; }
}

现在,对于一对一的关系,我不知道。 公共课家长 { 公共 int ID { 获取;放; }

   public int ChildID { get; set; }
   public virtual Child child { get; set; }
}

public class Child
{
   public int Id { get; set; }

   public int ParentId { get; set; } 
   public virtual Parent Parent { get; set; }
}

是否甚至需要外部 ID 属性,或者我可以在 Parent 类中拥有一个 Child 属性,在 Child 类中拥有一个 Parent-type 属性?当我省略外键 ID 属性时,是否允许使用 virtual 关键字?

【问题讨论】:

    标签: sql database entity-framework ef-code-first entity-framework-6


    【解决方案1】:

    使用实体框架,您甚至不必指定外键关系,因为它会从您的模型中推断出它并相应地创建表。您实际上必须做的唯一关系类型是 0..1 或 1 到 0..1 或 1。

    不要忘记对象模型比数据库模型更宽松。您可以拥有一个将集合存储在对象中而不是表中的属性。

    您必须有不同的想法,因为 EF 将在数据库级别为您完成工作,您将可以访问对象模型中定义的所有属性,甚至是集合属性。

    我一直用来完成它的规则如下:

    如果关系的基数是 0..1 或 1,则使用对其他实体对象的引用作为您的属性。如果基数很多,请使用集合。

    这里有一些用例:

    1 到很多(每个父母有很多孩子):

    public class Parent
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ICollection<Child> Childs { get; set; }
    }
    
    public class Child
    {
        public int Id { get; set; }
        // Navigation property
        public virtual Parent Parent { get; set; }
    }
    

    数据库中的结果将是一个具有单个属性(Id)的表Parent和一个具有两个属性的表Child,Id和外键属性自动生成命名为Parent_Id(表名然后下划线,然后是键属性相关类)。

    多对多:

    public class ClassA
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ICollection<ClassB> ClassBs { get; set; }
    }
    
    public class ClassB
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ICollection<ClassA> ClassAs { get; set; }
    }
    

    数据库中的结果将是具有单个属性 (Id) 的表 ClassA、具有单个属性 (Id) 的表 ClassB 和具有两个属性的第三个表(多对多关系的关系表)属性(这两个表的 ID)。

    EF 会推断出完成这项工作所需的内容,因此您不必再具体说明。

    现在是唯一有点问题的,1对1:

    public class ClassA
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ClassB ClassB { get; set; }
    }
    
    public class ClassB
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ClassA ClassA { get; set; }
    }
    

    按照我一开始给出的规则,这就是我们要做的。但是在这种情况下,EF 无法知道关系的方向...... 1 对 1 的 coule 可以是任一方向。我们将不得不使用注释让它知道方向(对我来说,与 Fluent API 相比是最简单的方法)。

    public class ClassA
    {
        public int Id { get; set; }
        // Navigation property
        public virtual ClassB ClassB { get; set; }
    }
    
    public class ClassB
    {
        [ForeignKey("ClassA")]
        public int Id { get; set; }
        // Navigation property
        public virtual ClassA ClassA { get; set; }
    }
    

    ClassB 中的注解 [ForeignKey("ClassA")] 告诉 EF 使用 ClassB 中的 Id 列作为 ClassA 中的外键。

    数据库中的结果将是具有 2 个属性(Id 和 ClassB_Id)的表 ClassA 和具有单个属性 (Id) 的表 ClassB。

    您不必自己创建外键属性,因为 EF 会为您完成。

    【讨论】:

      【解决方案2】:

      我建议你看看实体框架fluent api。使用 fluent api 可以轻松实现一对一的关系。 Explanation source。快速参考:

       public class Student
          {
              public Student() { }
      
              public int StudentId { get; set; }
              [Required]
              public string StudentName { get; set; }
      
              [Required]
              public virtual StudentAddress StudentAddress { get; set; }
      
          }
      
      
          public class StudentAddress 
          {
              [Key, ForeignKey("Student")]
              public int StudentId { get; set; }
      
              public string Address1 { get; set; }
              public string Address2 { get; set; }
              public string City { get; set; }
              public int Zipcode { get; set; }
              public string State { get; set; }
              public string Country { get; set; }
      
              public virtual Student Student { get; set; }
          }
      

      您可以在数据上下文类中覆盖 OnModelCreating。

       protected override void OnModelCreating(DbModelBuilder modelBuilder)
          {
              modelBuilder.Entity<StudentAddress>()
                  .HasKey(e => e.StudentId);
              modelBuilder.Entity<StudentAddress>()
                          .Property(e => e.StudentId)
                          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
              modelBuilder.Entity<StudentAddress>()
                          .HasRequired(e => e.Student)
                          .WithRequiredDependent(s => s.StudentAddress);
      
              base.OnModelCreating(modelBuilder);
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-07
        • 2021-12-14
        • 2022-09-23
        • 1970-01-01
        • 2021-08-15
        • 1970-01-01
        相关资源
        最近更新 更多