实体框架 - 关系混乱

时间:2014-10-02 07:12:26

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

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

一对多关系对我来说似乎很清楚:孩子们只需要一个foreignKey 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 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; }
}

现在,对于一对一关系,我不知道。     公共课家长     {        public int Id {get;组; }

   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属性,或者我可以在Child类中拥有Parent属性,在Parent类中拥有Child - 类型属性?当我省略外键ID属性时,是否允许virtual关键字?

2 个答案:

答案 0 :(得分:0)

我建议你看看实体框架流畅的api。使用流畅的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; }
    }

您可以在datacontext类中覆盖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);
    }

答案 1 :(得分:0)

使用Entity Framework,您甚至不必指定外键关系,因为它会从模型中推断出它并相应地创建表。您实际需要做的唯一关系类型是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)和具有两个属性的表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)的Table ClassA,具有单个属性(Id)的表ClassB和具有两个属性(Id)的第三个表(多对多关系的关系表)属性(这两个表的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无法知道关系的方向......一对一的方向是两个方向。我们必须让它知道使用注释的方向(对我而言,与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(&#34; ClassA&#34;)]告诉EF使用ClassB中的Id列作为ClassA中的外键。

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

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