首页 > 代码库 > 【译】第26节---配置一对多关系

【译】第26节---配置一对多关系

原文:http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx

本节,我们将学习如何在Code First中配置两个实体之间的一对多关系。

举一个Student和Standard(年级)实体的例子,其中,一个Standard可以包括许多Student。 所以Student与Standard实体之间的关系将是一对多的。

 

使用DataAnnotation配置一对多关系

来看下面Student与Standard实体:

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

上述示例中,Student实体包括导航属性Standard,Standard实体包括Student的集合属性。 这是形成一对多关系的默认约定。

如果实体类遵循此约定,则我们不需要使用DataAnnotations或Fluent API配置一对多关系。

EF Code First将通过在Student表中添加Standard_StandardId列来创建一对多关系,如下所示:

技术分享

 

实体包括外键Id属性:

建议在实体类中包含外键属性。 例如,Student实体包含自动变为foreignkey属性的StandardId属性,因为它符合外键<Type Name> Id的约定。

如果foreignkey属性名称不符合约定,例如,Student实体对于Standard实体使用了不同名称的外键(不是StandardId),那么我们需要在属性上应用ForeignKey属性。

例如,以下Student实体包括StandardRefId属性:

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

        public int StdandardRefId { get; set; }
        
    [ForeignKey("StandardRefId")]
    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

上述示例中,ForeignKey属性应用于Standard导航属性以指定Standard属性的foreignkey属性名称。所以EF将创建一个StandardRefId列作为FK,如下所示:

技术分享

 

使用Fluent API配置一对多关系

这里,我们将学习使用Fluent API的Student和Standard实体之间的一对多关系。

让我们为以下Student和Standard实体配置一对多关系:

public class Student
{
    public Student(){ }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public int StandardId { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        StudentsList = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

你可以按照一下代码进行配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasRequired<Standard>(s => s.Standard) // Student entity requires Standard 
                    .WithMany(s => s.Students); // Standard entity includes many Students entities

}

假设Student和Standard实体类没有遵循外键的Code First约定:

public class Student
{
    public Student(){ }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    //StdId is not following code first conventions name
    public int StdId { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        StudentsList = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

所以,你可以通过Fluent API使用Student实体类配置一对多关系,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasRequired<Standard>(s => s.Standard)
                    .WithMany(s => s.Students)
                    .HasForeignKey(s => s.StdId);

}

可以看到,modelBuilder.Entity <Student>().HasRequired <Standard>(s => s.Standard)指定Student实体需要NotNull标准导航属性。

.WithMany(s => s.Students).HasForeignKey(s => s.StdId)指定Standard实体可以包括多个Student在学生集合属性中,外键是StdId。

另一种可行的方式:我们也可以从Standard实体开始:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //configure one-to-many
        modelBuilder.Entity<Standard>()
                    .HasMany<Student>(s => s.Students) //Standard has many Students
                    .WithRequired(s => s.Standard)  //Student require one Standard
                    .HasForeignKey(s => s.StdId);//Student includes specified foreignkey property name for Standard
}

 上面的代码将创建以下数据库:

技术分享

注意StdId不为空列。 所以每次添加或更新Student时,都必须为Student实体指定Standard。

 

一对多关系中的可空外键:

使用HasOptional方法代替HasRequired方法使外键列为空。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasOptional<Standard>(s => s.Standard)
                    .WithMany(s => s.Students)
                    .HasForeignKey(s => s.StdId);

}

 

下节学习多对多关系的配置。

【译】第26节---配置一对多关系