EntityFramework Code-First 简易教程(八)-------一对一

配置一对一(One-to-One)关系:

两个实体中,如果一个实体的一个实例与另一个实体相关,则我们就叫做一对一关系

查看如下代码:

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类,所以符合一对一关系

在SQL Server数据库中,一对一关系发生在当一张表的主键是另一张表的主键或外键时,所以如上代码中,我们要配置StudentId为主键,StudentAddressId既为主键也为外键。

1.使用DataAnnotations配置一对零或一对一关系:

Student类会根据Code-First默认约定将StudentId属性配置为主键,所以这里我们就不用额外的配置它了。

StudentAddress类中,我们需要配置StudentAddressId既为主键又为外键,同样的,Code-First默认约定会将StudentAddressId配置为主键,所以这里我们仅仅需要使用[ForeignKey("Student")]特性将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 
{
    [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; }
}
View Code

 

这样,Student类和StudentAddress类就配置好了一对一关系。

如果StudentAddressId名称改变了,比如下面代码,改成了StudentId,默认就不会创建主键了,需要手动添加上[Key]特性:

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; }
}
View Code

这样,StudentAddress类中的StudentId就被配置为既是主键,又是外键。

注意: 虽然Student类中包含StudentAddress类属性,StudentAddress类中也包含Student类属性,但Student类的StudentAddress类属性可以为空,而StudentAddress类的Student类属性不能为空!如果保存一个Student类属性为空的StudentAddress类,会抛出异常。

 

 

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

下面我们将不使用任何DataAnnotations特性(虽然它们可以一起使用)仅仅使用Fluent API来配置一对一关系。

当Student类的命名和StudentAddress类的命名遵循默认约定的时候:

既然默认约定会自动为Student和StudentAddress创建主键,所以这里我们仅仅需要把StudentAddressId配置为外键

代码如下:

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实体的Address属性使用了HasOptional()方法,即Address属性不是必须的,可为空,又为StudentAddress类的Student属性使用了WithRequired()方法,即Student属性为必填,不能为空,如果存储StudentAddress实体的时候发现Student属性为空,则会抛出异常。

这样配置以后,StudentAddressId就已经是外键了。

当StudentAddress类的命名不遵循默认约定的时候:

如下代码,我们想要StudentAddress类的StudentId属性成为主外键

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; }
}

 

Fluent API配置如下:

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); 

}

 

 

3.使用Fluent API配置一对一关系:

说白了,所谓的一对一关系,即是两个实体类中作为主外键的类属性都不能为空。

注意:一对一关系在SQL Server中并不是必须,通常使用一对零或一对一。

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)使得Student类的Address属性为必须,WithRequiredPrincipal(ad => ad.Student) 方法使的StudentAddress类的Student属性为必须。

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

DataAnnotations and Fluent API都会创建如下的一对零或一对一关系的数据库:

one-to-one relationship in code first

我们可以检查Student表和StudentAddress表之间的关系:

one-to-one relationship in code first

图表关系如下

one-to-one relationship in code first

 

 

 

 

 啊啊啊啊啊,虽然最近忙成狗,但是说好的翻译,一定会坚持下去的!!!

posted @ 2016-06-07 20:58  唐大兵  阅读(1492)  评论(2编辑  收藏  举报