EF Code-First - Cấu hình mối quan hệ một-một
Cấu hình mối quan hệ một-một trong Entity Framework
Ở phần này, bạn sẽ tìm hiểu cách cấu hình mối quan hệ một-một giữa hai thực thể.
Chúng tôi sẽ thực hiện mối quan hệ một-một giữa thực thể Student
và StudentAddress
như sau:
public class 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; }
}
Mối quan hệ một-một xảy ra khi khóa chính của một bảng trở thành khóa chính và khóa ngoại của một bảng khác trong cơ sở dữ liệu quan hệ như SQL Server.
Vì vậy, chúng ta cần cấu hình các thực thể ở trên để EF tạo các bảng Students
và bảng StudentAddresses
trong DB.
Nó sẽ tạo cột StudentId
trong bảng Student
là khóa chính và cột StudentAddressId
trong bảng StudentAddresses
vừa là khóa chính vừa là khóa ngoại.
Cấu hình mối quan hệ một-một bằng cách sử dụng các attribute chú thích dữ liệu
Trong trường hợp này, chúng tôi sẽ sử dụng các thuộc tính chú thích dữ liệu trên các thực thể Student
và StudentAddress
để thiết lập mối quan hệ một-một.
Nếu bạn bỏ lỡ bài viết hướng dẫn cách sử dụng attribute chú thích dữ liệu thì có thể xem tại đây:
Thực thể Student
tuân theo quy ước mặc định của Code First vì nó có thuộc tính StudentId
sẽ là thuộc tính khóa.
Vì vậy, chúng ta không cần phải áp dụng bất kỳ attribute chú thích dữ liệu nào trên nó bởi vì EF sẽ tạo cột StudentId
là khóa chính của bảng Students
trong cơ sở dữ liệu.
Đối với thực thể StudentAddress
, chúng ta cần cấu hình StudentAddressId
vừa là khóa chính vừa là khóa ngoại.
Thuộc tính StudentAddressId
theo quy ước mặc định sẽ là khóa chính. Vì vậy, chúng ta không cần phải áp dụng bất kỳ attribute chú thích dữ liệu nào cho khóa chính.
Tuy nhiên, chúng ta cũng cần cấu hình nó là khóa ngoại của thực thể Student
.
Vì vậy, chúng ta sẽ khai báo [ForeignKey("Student")]
trên thuộc tính StudentAddressId
để cấu hình nó làm khóa ngoại cho thực thể Student
, như được trình bày dưới đây.
public class 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; }
}
Như vậy là bạn đã sử dụng attribute chú thích dữ liệu để cấu hình mối quan hệ một-một giữa hai thực thể.
Cấu hình mối quan hệ một-một bằng cách sử dụng Fluent API
Ở phần này, chúng tôi sẽ sử dụng Fluent API để định cấu hình mối quan hệ một-một giữa các thực thể Student
và StudentAddress
.
Nếu bạn bỏ lỡ bài viết hướng dẫn cách sử dụng Fluent API thì có thể xem ở đây:
Ví dụ sau đây thiết lập mối quan hệ một-một giữa Student
và StudentAddress
sử dụng Fluent API.
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
}
Trong ví dụ trên, chúng ta bắt đầu với thực thể Student
. Phương thức HasOptional()
cấu hình thuộc tính điều hướng Address
của thực thể Student
là tùy chọn (không bắt buộc khi lưu thực thể Student
).
Sau đó, phương thức WithRequired()
cấu hình thuộc tính điều hướng Student
của thực thể StudentAddress
là bắt buộc (bắt buộc phải có khi lưu thực thể StudentAddress
; nó sẽ đưa ra một ngoại lệ khi thực thể StudentAddress
được lưu mà không có thuộc tính điều hướng Student
). Điều này cũng sẽ làm cho cột StudentAddressId
trở thành khóa ngoại.
Như vậy là bạn đã biết cách cấu hình mối quan hệ một-một giữa hai thực thể bằng cách sử dụng Fluent API.
EF API sẽ tạo các bảng sau trong cơ sở dữ liệu.
Ở cách cấu hình trên, một thực thể Student
có thể được lưu mà không có thực thể StudentAddress
nhưng ngược lại thì không thể. EF sẽ đưa ra một ngoại lệ nếu bạn cố lưu thực thể StudentAddress
mà không có thực thể Student
.
Tuy nhiên chúng ta có thể cấu hình mối quan hệ một-một giữa các thực thể bằng Fluent API trong đó cả hai đầu đều bắt buộc.
Nghĩa là khi lưu một đối tượng thực thể Student
bắt buộc phải có đối tượng thực thể StudentAddress
và ngược lại.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure StudentId as FK for StudentAddress
modelBuilder.Entity<Student>()
.HasRequired(s => s.Address)
.WithRequiredPrincipal(ad => ad.Student);
}
Trong ví dụ trên, phương thức HasRequired(s => s.Address)
cấu hình thuộc tính Address
của thực thể StudentAddress
là bắt buộc và phương thức WithRequiredPrincipal(ad => ad.Student)
ấu hình thuộc tính Student
của thực thể StudentAddress
là bắt buộc.
Do đó, khi bạn cố gắng lưu thực thể Student
mà không có thực thể StudentAddress
hoặc ngược lại thì EF sẽ ném ra một ngoại lệ.
Tạo Mô hình dữ liệu thực thể chỉ đọc cho ví dụ trên bằng EF Power Tools. Các thực thể sẽ xuất hiện giống như sơ đồ được hiển thị bên dưới: