以以下 Student 和 StudentAddress 实体为例。
使用 DataAnnotations 配置一对零或一关系:
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; }
}
当 StudentAddress 实体不遵循约定时:
例如,如果 StudentAddress 实体不遵循 PK 的约定,即 Id 属性的不同名称,那么您还需要为 PK 配置它。考虑以下具有属性名称 StudentId 而不是 StudentAddressId 的 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
{
[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。
使用 Fluent API 配置一对零或一关系:
当 Student 和 StudentAddress 遵循约定时:
Student 和 StudentAddress 实体遵循 PrimaryKey 的默认代码优先约定。因此,我们不需要配置它们来定义它们的 PrimaryKey。我们只需要配置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 实体时需要,在没有Student 导航属性的情况下保存StudentAddress 实体时会抛出异常)。这将使 StudentAddressId 也成为 ForeignKey。
因此,您可以在两个实体之间配置一对零或一关系,其中可以在不附加 StudentAddress 对象的情况下保存 Student 实体,但如果不附加 Student 实体对象,则无法保存 StudentAddress 实体。这就需要一个末端。
当 StudentAddress 实体不遵循约定时:
现在,让我们以 StudentAddress 实体为例,它不遵循主键约定,即具有与 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; }
}
所以现在,我们需要为 StudentAddress 的 PrimaryKey 以及 ForeignKey 配置 StudentAddress 的 StudentId 属性,如下所示。
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.Student);
}
使用 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().HasRequired(s => s.Address) 使得 StudentAddress 的 Address 属性是必需的。 .WithRequiredPrincipal(ad => ad.Student) 根据需要生成 StudentAddress 实体的 Student 属性。因此,它配置了所需的两端。所以现在,当你尝试保存不带地址的 Student 实体或不带 Student 的 StudentAddress 实体时,它会抛出异常。
参考:http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx