8

Bir SQL Server 2012 express DB tarafından desteklenen Entity-Framework Core (sürüm "EntityFramework.Core": "7.0.0-rc1-final") ile bir ASP.NET MVC 6 projesinde çalışıyorum.Entity Framework Çekirdek Kod-İlk: Çoktan-çok ilişkide Cascade sil

Person öğesi ve Address varlığı arasında çoktan çoğa ilişkiyi modellemeye ihtiyacım var. this kılavuzuna göre PersonAddress birleşim tablosu öğesiyle modelledim, çünkü bu şekilde fazladan bilgi depolayabiliyorum. Bir Person örneği silinirse

  • , ilgili tüm PersonAddress örneklerini silinmesi gerekir:

    Benim gol set-up benim sistem bu şekilde olduğunu. Başvuruda bulundukları tüm Address örneklerinin de, yalnızca diğer PersonAddress örnekleri ile ilişkili olmadıklarında silinmesi gerekir.

  • PersonAddress örneği silinirse, ilgili Address örneğinin, yalnızca diğer PersonAddress örnekleri ile ilgili değilse silinmesi gerekir. Tüm Person örneklerinin canlı olması gerekir.
  • Address örneği silinirse, ilgili tüm PersonAddress örneklerinin silinmesi gerekir. Tüm Person örneklerinin canlı olması gerekir.

Ben işin çoğunu Person ve Address arasında birçok çoğa ilişkide yapılmalıdır düşünüyorum, ama ben de bazı mantık yazmak için bekliyoruz. Bu bölümü bu sorudan çıkaracağım. İlgilendiğim şey, çoktan çoğa ilişkilerimi nasıl yapılandıracağım.

Güncel durumu. Bu bir Person öğesidir. Bu öğenin diğer ikincil varlıklar ile bire çok ilişkisi olduğunu lütfen unutmayın.

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 
} 

Bu, Address öğedir.

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 
} 

Bu PersonAddress varlıktır.

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 
} 

Bu tüm ilişkiler açıklanmıştır DatabaseContext varlıktır.

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

Hem Telephone ve City kişiler basitlik amacıyla kaldırıldı.

Bu, Person'un kaldırılmasına yönelik koddur. DB nihai CASCADE siler özen sağlayacak .Include() kaçınarak benim okumalar gelince

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

} 

. Üzgünüm ama bu kavramın açıklığa kavuşturulduğu SO sorusunu hatırlamıyorum.

Bu kodu çalıştırırsam, DB'yi this workaround kullanarak ekilebilir.Ben sınamak-silmeden yukarıdaki kod ile bir Person varlık istediğinizde, bu durum almak:

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. 

Ben olmadan herhangi bir şans DatabaseContext.OnModelCreating yöntemde birçok ilişki kurulumları test etti.

Son olarak, işte soru. Daha önce açıklanan hedef hedefine göre, bir Person ve ilgili varlıklarını uygulamadan doğru bir şekilde silmek için çoktan çoğa ilişkimi nasıl yapılandırmalıyım?

Hepinize teşekkürler.

cevap

0

Önce sen DeleteBehavior.Restrict ile Şehir ve Adres ilişki kurdunuz görmek ve de ki: '// Ben Adres silmek Şehir silmek istemiyoruz'.
Ancak burada kısıtlamanız gerekmez, çünkü DeleteBehavior.Cascade City ile bile silinmez. Yanlış tarafa bakıyorsunuz. Cascade Burada bir Şehir silindiğinde, kendisine ait tüm adresler de silinir. Ve bu davranış mantıklı.

İkinci olarak çoktan çoğa ilişkiniz iyidir. Kişiyi silerken PersonAddress Tablosundan bağlantıları Bağlanma nedeniyle otomatik olarak silinecektir. Ayrıca, sadece o kişiye bağlı olan Adresleri de silmek isterseniz, bunu manuel olarak yapmanız gerekecektir. Gerçekten silmeden önce bu Adresleri silmeniz gerekir Kişi neyi silmeyi bilmek için emirdir.
Dolayısıyla mantık aşağıdaki gibi olmalıdır: PersonId = person.Id; PersonAddress'in tüm kayıtlarını sorgulayın;
2. Bunlar yalnızca PersonAddress tablosunda AddressId öğesinin tek bir zamanını geçirenleri alır ve bunları Kişiler tablosundan siler.
3. Şimdi Kişiyi silin.

doğrudan kodda bu yapabileceğini veya veritabanı sizin için bunu yapmak istiyorum, tetik fonksiyonu ile 2. adımda için oluşturulabilir: artık yoksa PersonAddress gelen satır çeki silinmek üzere olduğunda Bu AddressAdd içinde aynı AddressId satırları, bu durumda Adres tablosundan silin. Burada

diğer bilgiler:
How to cascade delete over many to many table
How do I delete from multiple tables using INNER JOIN in SQL server