One-to-many relationship
前言
在設計table之間的關係,不外乎是一對多(one-to-many relationship)、一對一(one-to-one relationship)、多對多(many-to-many relationship)的設計,這些設計也是能夠在Code First完成的。 今天就先來分享one-to-many relationship。
Convention
- Domain class包含其他 Domain class property或者包含其他collection Domain class property,Code First會預設為one-to-many relationship
- 或者兩個Domain classes其中一個包含navigation property,Code First都會預設為one-to-many relationship
備註:包含其他Domain class property我們稱之為Navigation Property
範例如下:
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
/// <summary>
/// Navigation Proerty
/// </summary>
public ICollection<Course> Courses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
/// <summary>
/// Navigation Proerty
/// </summary>
public Student Student { get; set; }
}
Required
從上面對應資料庫的情形可以知道,Course產生的foreign key是可以null的,意思就是說這種設計方式Course可以不包含任何學生,看起來有點不合理,所以在這邊要記得設定Required Data Annotation,讓foreign key為 not null。
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
[Required]
public Student Student { get; set; }
}
備註:[Required]如果設在ICollection navigation property是沒有效果的。
Configuring with the Fluent API
使用Fulent API達成一樣效果的範例如下:
Pattern : Entity.Has[Multiplicity](Property).With[Multiplicity](Property)
public class StudentConfiguration : EntityTypeConfiguration<Student>
{
public StudentConfiguration()
{
//Student 有很多 Course
HasMany<Course>(x => x.Courses)
//且Course一定要包含Student
.WithRequired(x => x.Student);
}
}
指定Foreign Key
到目前為止,都是Code First根據預設pattern幫我們指定foreign key,所以才會產生Student_StudentId這個名稱。 而如果要自己產生指定的foreign key也是很簡單,只要再加上一個property就可以了。
三種指定foreign key convention
- [Target Type Key Name]
- [Target Type Name] + [Target Type Key Name]
- [Navigation Property Name] + [Target Type Key Name].
使用第一種Convention範例如下:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
/// <summary>
/// Foreign Key
/// </summary>
public int StudentId { get; set; }
public Student Student { get; set; }
}
產生對應的資料庫table,會發現foreign key怎麼會是非null? 這是因為StudentId的型別是int,所以是不能assigned nul。如果把型別改成Nullable<int>則StudentId會變為可null的 foreign key。
Unconvention Foreign Key
如果自己指定的foreign key命名不符合Convention,則Code First還是會自己產生一個foreign key欄位,如下:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
/// <summary>
/// Foreign Key
/// </summary>
public int SchoolStudentId { get; set; }
public Student Student { get; set; }
}
此時我們可以用ForeignKey Data Annotation來指定foreign key
方法一:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
/// <summary>
/// Foreign Key
/// </summary>
[ForeignKey("Student")]
public int SchoolStudentId { get; set; }
public Student Student { get; set; }
}
方法二:
public class Course
{
public int CourseId { get; set; }
public string Name { get; set; }
/// <summary>
/// Foreign Key
/// </summary>
public int SchoolStudentId { get; set; }
[ForeignKey("SchoolStudentId")]
public Student Student { get; set; }
}
這兩種方法對應出來的資料庫結果都是一樣的,如下:
Configuring with the Fluent API
方法一:
在StudentConfiguration設定。 還記得剛剛設定的WithRequired嗎,只要在後面加上HasForeignKey的設定就好了。
public class StudentConfiguration : EntityTypeConfiguration<Student>
{
public StudentConfiguration()
{
HasMany<Course>(x => x.Courses)
.WithRequired(x => x.Student)
.HasForeignKey<int>(x => x.SchoolStudentId);
}
}
方法二:
在CourseConfiguration設定
public class CourseConfiguration : EntityTypeConfiguration<Course>
{
public CourseConfiguration()
{
HasRequired<Student>(x => x.Student)
.WithMany(x => x.Courses)
.HasForeignKey<int>(x => x.SchoolStudentId);
}
}
小節:
one-to-many relationship已經介紹的差不多了,用法不外乎這幾種。 接下來幾篇會繼續介紹one-to-one relationship與many-to-many relationship。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。