EF Code-First - Cascade Delete
Cascade Delete trong Code First
Cascade Delete sẽ tự động xóa các bản ghi phụ thuộc hoặc thiết lập các cột khóa ngoại thành null khi bản ghi cha bị xóa trong cơ sở dữ liệu.
Cascade Delete được bật theo mặc định trong Entity Framework cho tất cả các loại mối quan hệ, chẳng hạn như một-một, một-nhiều và nhiều-nhiều.
Cascade Delete trong mối quan hệ một-một
Hãy xem ví dụ sau đây: các thực thể Student
và StudentAddress
có mối quan hệ một-một.
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; }
}
Ví dụ sau đây minh họa cascade delete.
using (var ctx = new SchoolContext())
{
var stud = new Student() { StudentName = "James" };
var add = new StudentAddress() { Address1 = "address" };
stud.Address = add;
ctx.Students.Add(stud);
ctx.SaveChanges();
ctx.Students.Remove(stud);// student and its address will be removed from db
ctx.SaveChanges();
}
Trong ví dụ trên, đầu tiên EF lưu đối tượng stud
của thực thể Student
và đối tượng add
của thực thể StudentAddress
của nó vào cơ sở dữ liệu.
Sau đó, khi xóa đối tượng stud
và gọi phương thức SaveChanges()
, EF sẽ xóa stud
cũng như bản ghi tương ứng của nó trong bảng StudentAddresses
.
Do đó, EF cho phép cascade delete theo mặc định.
Cascade Delete trong mối quan hệ một-nhiều
Hãy xem ví dụ sau đây: các thực thể Student
và Standard
có mối quan hệ một-nhiều.
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Ví dụ sau đây minh họa cascade delete giữa các thực thể có mối quan hệ một-nhiều:
using (var ctx = new SchoolContext())
{
var student1 = new Student() { StudentName = "James" };
var student2 = new Student() { StudentName = "Gandhi" };
var standard1 = new Standard() { StandardName = "Standard 1" };
student1.Standard = standard1;
student2.Standard = standard1;
ctx.Students.Add(student1);
ctx.Students.Add(student2);
//inserts students and standard1 into db
ctx.SaveChanges();
//deletes standard1 from db and also set standard_StandardId FK column in Students table to null for
// all the students that reference standard1.
ctx.Standards.Remove(standard1);
ctx.SaveChanges();
}
Trong ví dụ trên, EF xóa đối tượng standard1
khỏi cơ sở dữ liệu và nó cũng thiết lập cột khóa ngoại standard_StandardId
trong bảng Students
thành null cho tất cả các bản ghi tham chiếu đối tượng standard1
.
Lưu ý: EF tự động xóa các bản ghi liên quan trong bảng ở giữa cho các thực thể có mối quan hệ nhiều-nhiều nếu một thực thể bị xóa.
Do đó, EF cho phép cascade delete mặc định cho tất cả các thực thể.
Tắt Cascade Delete
Sử dụng Fluent API để cấu hình tắt cascade delete cho các thực thể để bằng phương thức WillCascadeOnDelete()
, như ví dụ bên dưới.
public class SchoolContext<: DbContext
{
public SchoolContext():base("MySchool")
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasOptional<Standard>(s => s.Standard)
.WithMany()
.WillCascadeOnDelete(false);
}
}