8

Pracuję nad projektem ASP.NET MVC 6 z Entity-Framework Core (wersja "EntityFramework.Core": "7.0.0-rc1-final") wspieranym przez DB Express serwera SQL Server 2012.Entity Framework Core Code-First: Cascade delete dla relacji wielu do wielu

Muszę modelować relację wiele do wielu między jednostką Person a jednostką Address. Zgodnie z instrukcją , zamodelowałem ją za pomocą encji łączenia tabeli PersonAddress, ponieważ w ten sposób mogę przechowywać dodatkowe informacje.

Moja celem jest set-up mój system w ten sposób:

  • Jeśli instancja Person zostanie usunięte, wszystkie związane PersonAddress przypadki muszą zostać usunięte. Wszystkie instancje, do których się odwołują, muszą być również usunięte, tylko jeśli nie są powiązane z innymi instancjami PersonAddress.
  • Jeśli instancja PersonAddress zostanie usunięta, instancja Address, z którą się ona odnosi, musi zostać usunięta, tylko jeśli nie jest powiązana z innymi instancjami PersonAddress. Wszystkie instancje Person muszą żyć.
  • Jeśli instancja Address zostanie usunięta, wszystkie powiązane instancje PersonAddress muszą zostać usunięte. Wszystkie instancje Person muszą żyć.

myślę większość pracy muszą być wykonane w wielu do wielu relacji między Person i Address, ale spodziewam się, aby napisać jakąś logikę też. Opuszczę tę część z tego pytania. Interesuje mnie to, jak skonfigurować moją relację wiele do wielu.

Oto aktualna sytuacja.

To jest jednostka Person. Pamiętaj, że ta jednostka ma relacje jeden-do-wielu z innymi obiektami dodatkowymi. Jest to encja Address. Jest to jednostka . Jest to jednostka DatabaseContext, w której opisane są wszystkie relacje.

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(); 
    } 
} 

Oba Telephone i City podmioty zostały usunięte ze względu na prostotę. To jest kod do usuwania Person.

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

} 

Co do moich odczytów unikając .Include() pozwoli DB dbać o ewentualnych CASCADE usuwaniem. Przykro mi, ale nie pamiętam odpowiedzi na pytanie, gdzie ta koncepcja została wyjaśniona.

Po uruchomieniu tego kodu mogę zasiać DB za pomocą this workaround.Kiedy chcę przetestować-usuwanie Person podmiot z powyższym kodzie, otrzymuję ten wyjątek:

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. 

Przetestowałem kilka ustawień relacji w metodzie DatabaseContext.OnModelCreating bez powodzenia.

Wreszcie, tutaj jest moje pytanie. Jak mam skonfigurować relację wiele do wielu, aby poprawnie usunąć Person i powiązane z nią elementy z mojej aplikacji, zgodnie z opisaną wcześniej wersją gol?

Dziękuję wszystkim.

Odpowiedz

0

Najpierw widzę ustawiono Miasto i Adres relację z DeleteBehavior.Restrict i mówisz: „// Nie chcę, aby usunąć Miasto kiedy usunąć adres”.
Ale nie musisz tutaj ograniczać, ponieważ nawet z DeleteBehavior.Cascade miasto nie zostanie usunięte. Patrzysz na to po złej stronie. To, co tutaj robi to Cascade, kiedy miasto jest usuwane, usuwa również wszystkie adresy należące do niego. To zachowanie jest logiczne.

Po drugie, twoja relacja wiele do wielu jest w porządku. Podczas usuwania osoby jego linki z tabeli PersonAddress zostaną automatycznie usunięte z powodu Kaskady. A jeśli chcesz również usunąć adresy, które były połączone tylko z tą osobą, musisz to zrobić ręcznie. Musisz faktycznie usunąć te adresy przed usunięciem Osoba, aby wiedzieć, co usunąć.
Tak więc logika powinna być następująca:
1. Zapytanie przez cały rekord PersonAddress, gdzie PersonId = person.Id;
2. Spośród tych, które mają tylko jedno wystąpienie AddressId w tabeli PersonAddress, i usuń je z tabeli Person.
3. Teraz usuń osobę.

Możesz to zrobić bezpośrednio w kodzie lub jeśli chcesz, aby baza danych zrobiła to za Ciebie, można utworzyć wyzwalacz dla kroku 2 z funkcją: Kiedy wiersz z PersonAddress ma zostać usunięty, sprawdź, czy nie ma więcej wiersze o tym samym AddressId w tej tabeli PersonAddress, w takim przypadku usuń go z tabeli Address.

Więcej informacji tutaj:
How to cascade delete over many to many table
How do I delete from multiple tables using INNER JOIN in SQL server