實體框架核心代碼優先:在多對多關係上級聯刪除

c# code-first ef-code-first entity-framework entity-framework-core

我正在使用SQL Server 2012 Express DB支持的Entity-Framework Core(版本"EntityFramework.Core": "7.0.0-rc1-final" )的ASP.NET MVC 6項目。

我需要模擬Person實體和Address實體之間的多對多關係。根據指南,我使用PersonAddress連接表實體對其進行建模,因為這樣我可以存儲一些額外的信息。

我的目標是以這種方式設置我的系統:

  • 如果刪除Person實例,則必須刪除所有相關的PersonAddress實例。只有當它們與其他PersonAddress實例無關時,它們引用的所有Address實例也必須被刪除。
  • 如果PersonAddress實例被刪除,該Address涉及實例必須只有當它不與其他刪除PersonAddress實例。所有Person實例都必須存在。
  • 如果刪除了Address實例,則必須刪除所有相關的PersonAddress實例。所有Person實例都必須存在。

我認為大多數工作必須在PersonAddress之間的多對多關係中完成,但我希望也寫一些邏輯。我將把這一部分從這個問題中解脫出來。我感興趣的是如何配置我的多對多關係。

這是目前的情況

這是Person實體。請注意,此實體與其他輔助實體之間存在一對多關係。

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
}

這是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
}

這是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
}

這是DatabaseContext實體,其中描述了所有關係。

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

為簡單起見, TelephoneCity實體都已刪除。

這是刪除Person的代碼。

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

}

至於我的讀數,避免.Include()將讓DB處理最終的CASCADE刪除。對不起,但我不記得這個概念澄清的問題。

如果我運行此代碼,我可以使用此解決方法為數據庫播種。當我想使用上面的代碼測試刪除Person實體時,我得到以下異常:

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.

我在DatabaseContext.OnModelCreating方法中測試了幾個關係設置而沒有任何運氣。

最後,這是我的問題 。根據之前描述的目標 ,我應該如何配置我的多對多關係,以便從我的應用程序中正確刪除Person及其相關實體?

謝謝你們。

一般承認的答案

首先,我看到你已經設置了與DeleteBehavior.Restrict 城市地址關係,你說:' //我刪除地址時不想刪除城市 '。
但是你不需要在這裡限制,因為即使使用DeleteBehavior.Cascade City也不會被刪除。你是從錯誤的一面看。 Cascade在這裡做的是當刪除城市時,所有屬於它的地址也被刪除。這種行為是合乎邏輯的。

其次,你的多對多關係很好。刪除Person時,由於Cascade,將自動刪除PersonAddress Table中的鏈接。如果您還想刪除僅與該Person連接的地址,則必須手動執行此操作。在刪除Person之前,您實際上必須刪除這些地址,以便知道要刪除的內容。
所以邏輯應遵循:
1.查詢PersonAddress的所有記錄,其中PersonId = person.Id ;
2.那些只接受在PersonAddress表中單獨出現AddressId的那些,並從Person表中刪除它們。
3.現在刪除Person。

您可以直接在代碼中執行此操作,或者如果您希望數據庫為您執行此操作,可以使用函數為步驟2創建觸發器:當要刪除PersonAddress中的行時,檢查是否沒有更多具有相同AddressId的行PersonAddress表,在這種情況下從Address表中刪除它。

更多信息:
如何級聯刪除多對多表
如何在SQL Server中使用INNER JOIN從多個表中刪除



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因