两个实体中,若是一个实体的一个实例与另外一个实体相关,则咱们就叫作一对一关系数据库
查看以下代码:ide
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类,因此符合一对一关系ui
在SQL Server数据库中,一对一关系发生在当一张表的主键是另外一张表的主键或外键时,因此如上代码中,咱们要配置StudentId为主键,StudentAddressId既为主键也为外键。spa
Student类会根据Code-First默认约定将StudentId属性配置为主键,因此这里咱们就不用额外的配置它了。.net
StudentAddress类中,咱们须要配置StudentAddressId既为主键又为外键,一样的,Code-First默认约定会将StudentAddressId配置为主键,因此这里咱们仅仅须要使用[ForeignKey("Student")]特性将StudentAddressId属性配置为外键便可。翻译
代码以下:code
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类就配置好了一对一关系。blog
若是StudentAddressId名称改变了,好比下面代码,改为了StudentId,默认就不会建立主键了,须要手动添加上[Key]特性:ip
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; } }
这样,StudentAddress类中的StudentId就被配置为既是主键,又是外键。ci
注意: 虽然Student类中包含StudentAddress类属性,StudentAddress类中也包含Student类属性,但Student类的StudentAddress类属性能够为空,而StudentAddress类的Student类属性不能为空!若是保存一个Student类属性为空的StudentAddress类,会抛出异常。
下面咱们将不使用任何DataAnnotations特性(虽然它们能够一块儿使用)仅仅使用Fluent API来配置一对一关系。
既然默认约定会自动为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类的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); }
说白了,所谓的一对一关系,便是两个实体类中做为主外键的类属性都不能为空。
注意:一对一关系在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都会建立以下的一对零或一对一关系的数据库:
咱们能够检查Student表和StudentAddress表之间的关系:
图表关系以下
啊啊啊啊啊,虽然最近忙成狗,可是说好的翻译,必定会坚持下去的!!!