8

Tôi đang làm việc trên một dự án ASP.NET MVC 6 với Entity-Framework Core (phiên bản "EntityFramework.Core": "7.0.0-rc1-final") được hỗ trợ bởi một SQL Server 2012 Express DB.Cấu trúc thực thể Core Code-First: Cascade delete trên mối quan hệ nhiều-nhiều

Tôi cần lập mô hình mối quan hệ nhiều-nhiều giữa một thực thể Person và thực thể Address. Theo hướng dẫn của this tôi đã mô hình hóa nó với một thực thể kết hợp PersonAddress, bởi vì theo cách này tôi có thể lưu trữ một số thông tin bổ sung.

Mục tiêu của tôi là để thiết lập hệ thống của tôi theo cách này:

  • Nếu một trường hợp Person bị xóa, tất cả các liên quan PersonAddress trường hợp phải được xóa. Tất cả các trường hợp Address mà chúng tham chiếu đến cũng phải bị xóa, chỉ khi chúng không liên quan đến các trường hợp PersonAddress khác.
  • Nếu một phiên bản PersonAddress bị xóa, trường hợp Address liên quan đến nó phải bị xóa chỉ khi nó không liên quan đến các trường hợp PersonAddress khác. Tất cả các trường hợp Person phải hoạt động.
  • Nếu một phiên bản Address bị xóa, tất cả các phiên bản PersonAddress liên quan phải được xóa. Tất cả các trường hợp Person phải hoạt động.

Tôi nghĩ hầu hết công việc phải được thực hiện trong mối quan hệ nhiều-nhiều giữa PersonAddress, nhưng tôi cũng mong đợi viết một số logic. Tôi sẽ để phần này ra khỏi câu hỏi này. Những gì tôi quan tâm là làm thế nào để cấu hình mối quan hệ nhiều-nhiều của tôi.

Đây là tình huống hiện tại.

Đây là thực thể Person. Xin lưu ý rằng thực thể này có mối quan hệ một-nhiều với các thực thể phụ khác.

public class Person 
{ 
    public int Id {get; set; } //PK 
    public virtual ICollection<Telephone> Telephones { get; set; } //navigation property 
    public virtual ICollection<PersonAddress> Addresses { get; set; } //navigation property for the many-to-many relationship 
} 

Đây là thực thể Address.

public class Address 
{ 
    public int Id { get; set; } //PK 
    public int CityId { get; set; } //FK 
    public City City { get; set; } //navigation property 
    public virtual ICollection<PersonAddress> People { get; set; } //navigation property 
} 

Đây là thực thể PersonAddress.

public class PersonAddress 
{ 
    //PK: PersonId + AddressId 
    public int PersonId { get; set; } //FK 
    public Person Person {get; set; } //navigation property 
    public int AddressId { get; set; } //FK 
    public Address Address {get; set; } //navigation property 
    //other info removed for simplicity 
} 

Đây là thực thể DatabaseContext, nơi tất cả các mối quan hệ được mô tả.

public class DataBaseContext : DbContext 
{ 
    public DbSet<Person> People { get; set; } 
    public DbSet<Address> Addresses { get; set; } 

    protected override void OnModelCreating(ModelBuilder builder) 
    {    
     //All the telephones must be deleteded alongside a Person. 
     //Deleting a telephone must not delete the person it refers to. 
     builder.Entity<Person>() 
      .HasMany(p => p.Telephones) 
      .WithOne(p => p.Person); 

     //I don't want to delete the City when I delete an Address 
     builder.Entity<Address>() 
      .HasOne(p => p.City) 
      .WithMany(p => p.Addresses) 
      .IsRequired().OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Restrict); 

     //PK for the join entity 
     builder.Entity<PersonAddress>() 
      .HasKey(x => new { x.AddressId, x.PersonId }); 

     builder.Entity<PersonAddress>() 
      .HasOne(p => p.Person) 
      .WithMany(p => p.Addresses) 
      .IsRequired(); 

     builder.Entity<PersonAddress>() 
      .HasOne(p => p.Address) 
      .WithMany(p => p.People) 
      .IsRequired(); 
    } 
} 

Cả hai đối tượng TelephoneCity đều đã bị xóa để đơn giản.

Đây là mã để xóa Person.

Person person = await _context.People.SingleAsync(m => m.Id == id); 
try 
{ 
    _context.People.Remove(person); 
    await _context.SaveChangesAsync(); 
} 
catch (Exception ex) 
{ 

} 

Đối với bài đọc của tôi tránh .Include() sẽ cho DB chăm sóc CASCADE xóa cuối cùng. Tôi xin lỗi nhưng tôi không nhớ câu hỏi SO mà khái niệm này đã được làm rõ.

Nếu tôi chạy mã này, tôi có thể hạt giống DB bằng cách sử dụng this workaround.Khi tôi muốn kiểm tra-xóa một thực thể Person với đoạn code trên, tôi nhận được ngoại lệ này:

The DELETE statement conflicted with the REFERENCE constraint "FK_PersonAddress_Person_PersonId". The conflict occurred in database "<dbName>", table "<dbo>.PersonAddress", column 'PersonId'. 
The statement has been terminated. 

Tôi đã thử nghiệm một vài thiết lập mối quan hệ trong phương pháp DatabaseContext.OnModelCreating mà không cần bất kỳ may mắn.

Cuối cùng, đây là câu hỏi của tôi. Tôi nên định cấu hình quan hệ nhiều-nhiều của mình như thế nào để xóa chính xác một số Person và các thực thể liên quan khỏi ứng dụng của tôi, theo mục tiêu được mô tả trước đây?

Cảm ơn tất cả.

Trả lời

0

Trước tiên tôi thấy bạn đã thiết lập Thành phốĐịa chỉ mối quan hệ với DeleteBehavior.Restrict và bạn nói: '// Tôi không muốn xóa các thành phố khi tôi xóa một địa chỉ'.
Nhưng bạn không cần Hạn chế ở đây, bởi vì ngay cả với DeleteBehavior.Cascade Thành phố sẽ không bị xóa. Bạn đang tìm kiếm từ phía sai. Điều gì Cascade ở đây là khi một Thành phố bị xóa, tất cả các địa chỉ thuộc về nó cũng bị xóa. Và hành vi đó là hợp lý.

Thứ hai mối quan hệ nhiều-nhiều của bạn là tốt. Khi xóa người, các liên kết của nó từ Bảng PersonAddress sẽ tự động bị xóa vì Cascade. Và nếu bạn cũng muốn xóa Địa chỉ chỉ được kết nối với Người đó, bạn sẽ phải thực hiện thủ công. Bạn thực sự phải xóa những Địa chỉ đó trước khi xóa Người để biết phải xóa những gì.
Vì vậy, logic phải tuân theo:
1. Truy vấn thông qua tất cả hồ sơ của PersonAddress nơi PersonId = person.Id;
2. Trong số những người chỉ có những người có duy nhất xảy ra AddressId trong bảng PersonAddress, và xóa chúng khỏi bảng Person.
3. Bây giờ hãy xóa Người.

Bạn có thể thực hiện điều này bằng mã trực tiếp hoặc nếu bạn muốn cơ sở dữ liệu thực hiện điều đó cho bạn, trình kích hoạt có thể được tạo cho bước 2 với hàm: Khi hàng từ PersonAddress sắp bị xóa kiểm tra nếu không còn các hàng có cùng AddressId trong bảng PersonAddress đó, trong trường hợp này xóa nó khỏi bảng Address. Thông tin

More đây:
How to cascade delete over many to many table
How do I delete from multiple tables using INNER JOIN in SQL server

Các vấn đề liên quan