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

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

本节,我们将配置两个实体之间的一对零或者一对一关系。例如, Entity1可以与零个或仅一个Entity2实例相关联。

举个例子,来看以下的Student和StudentAddress实体。

public class Student
{
    public Student() { }

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

    public virtual StudentAddress Address { get; set; }

}
     
public class StudentAddress 
{
    public int StudentAddressId { 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; }
}

现在,我们将Student和StudentAddress实体配置为一对零或一对一关系,学生可以拥有零个或最多一个StudentAddress。

你可能知道,当一个表的主键在关系数据库(如SQL Server)中的另一个表中变为PK&FK时,会发生一对零或一对一关系。

所以,我们需要配置上面的实体,使得EF在DB中创建Student和StudentAddresses表。其中,将StudentID在Student表中作为PK,StudentAddressId在StudentAddress表中作为PK和FK。

使用数据注解配置一对零或一对一关系

这里,我们将在Student和StudentAddress实体上应用DataAnnotations属性来建立一对一的关系。

>>当Student和StudentAddress实体遵循约定:

学生实体遵循默认的Code-First约定,因为它包含将是key属性的StudentId属性。 因此,我们不需要应用任何属性,因为EF将创建Student表,并将StudentId作为数据库中的主键。

对于StudentAddress实体,我们需要将StudentAddressId配置为PK&FK。 StudentAddressId属性遵循主键的默认约定。 所以我们不需要为PK应用任何属性。而我们还需要使它成为一个指向StudentId的外键。 所以,在StudentAddressId属性中应用[ForeignKey(“Student”)],使之成为Student实体的外键。如下所示:

public class Student
{
    public Student() { }

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

    public virtual StudentAddress Address { get; set; }

}
     
public class StudentAddress 
{
    [ForeignKey("Student")]
    public int StudentAddressId { 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; }
}

因此,Student和StudentAddress实体具有一对零或一对一的关系。

>>当StudentAddress实体没有遵循约定:

如果StudentAddress实体不符合PK的约定,即Id属性的不是你想要的,那么你还需要为它配置PK。 看下面的StudentAddress实体,它的属性名称为StudentId而不是StudentAddressId。

public class Student
{
    public Student() { }

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

    public virtual StudentAddress Address { 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; }
}

上面的例子中,我们需要将StudentId属性配置为Key以及ForeignKey。 这将使StudentAddress实体中的StudentId属性成为PK和FK。

注意:Student包括StudentAddress导航属性,StudentAddress包括学生导航属性。

使用一对零或一对一关系,没有StudentAddress实体时,可以保存Student实体。

但没有Student实体时,StudentAddress实体无法保存。如果你试着保存没有Student实体的StudentAddress实体,EF将抛出异常。

使用Fluent API配置一对零或一对一关系

这里,我们将使用Fluent API配置Student和StudentAddress实体。 注意,我们不会在Student和StudentAddress实体中应用任何DataAnnotations属性,因为我们将使用Fluent API进行配置。

>>当Student和StudentAddress实体遵循约定:

Student和StudentAddress实体遵循PrimaryKey的默认代码优先约定。 所以,我们不需要配置它们来定义它们的PrimaryKeys。 我们只需要配置StudentAddress实体,将StudentAddressId设置为ForeignKey。

以下示例使用Fluent API在Student和StudentAddress之间设置一对零或一对一关系:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure Student & StudentAddress entity
    modelBuilder.Entity<Student>()
                .HasOptional(s => s.Address) // Mark Address property optional in Student entity
                .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student

}

上述示例中,Student实体使用HasOptional()方法进行配置,该方法指示Student实体中的StudentAddress导航属性是可选的(保存Student实体时不需要)。

然后,WithRequired()方法配置StudentAddress实体,使StudentAddress的Student导航属性为必需的(保存StudentAddress实体时需要,当StudentAddress实体保存时不包含Student导航属性,它将抛出异常)。 这也将使StudentAddressId为ForeignKey。

因此,你可以在两个实体之间配置一对零或者一对一的关系,其中,可以保存Student实体时而不将StudentAddress对象附加到该实体,但是无法保存StudentAddress实体而不附加Student实体的对象。 这使得一端实体为必需的。

>>当StudentAddress实体没有遵循约定:

现在,我们举一个StudentAddress实体的例子,它不遵循主键约定,即具有与<type name> Id不同的Id属性名称。 看以下Student和StudentAddress实体:

public class Student
{
    public Student() { }

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

    public virtual StudentAddress Address { get; set; }

}
     
public class StudentAddress 
{
    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; }
}

所以现在,我们需要配置StudentId属性为StudentAddress实体的主键和外键,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure StudentId as PK for StudentAddress
    modelBuilder.Entity<StudentAddress>()
        .HasKey(e => e.StudentId);
        
    // Configure StudentId as FK for StudentAddress
    modelBuilder.Entity<Student>()
                .HasOptional(s => s.Address) 
                .WithRequired(ad => ad.StudentId); 

}

使用Fluent API配置一对一关系

我们可以使用Fluent API配置实体之间的一对一关系,其中两端都是必需的,这意味着保存的时候,Student实体对象必须包含StudentAddress实体对象,并且StudentAddress实体必须包含Student实体对象。

注意:在MS SQL Server中技术上无法实现一对一的关系。 它一直是一到零或一对一。 EF在实体上形成一对一的关系,而不是在不在DB中。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure StudentId as PK for StudentAddress
    modelBuilder.Entity<StudentAddress>()
        .HasKey(e => e.StudentId);
        
    // Configure StudentId as FK for StudentAddress
    modelBuilder.Entity<Student>()
                .HasRequired(s => s.Address) 
                .WithRequiredPrincipal(ad => ad.Student); 

}

在上面的例子中,modelBuilder.Entity <Student>().HasRequired(s => s.Address)使得StudentAddress的Address属性是必需的。

.WithRequiredPrincipal(ad => ad.Student)使StudentAddress实体的Student属性成为必需的。

因此,它配置两端都是必需的。

所以现在,当你尝试保存没有Student的StudentAddress实体或者没有StudentAddress的Student时,它会抛出异常。

注意:这里,主体实体是Student,依赖实体是StudentAddress。

使用DataAnnotations和Fluent API配置一对零或一对一关系的示例将创建以下数据库:

 

你可以检查数据库中Student和StudentAddress之间的关系,如下所示:

如果表示一个“创建的数据库的实体数据模型”,那么它将如下图所示:

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

原文地址:https://www.cnblogs.com/talentzemin/p/7274290.html