簡體   English   中英

EF種子多對多相關表

[英]EF Seed Many-to-Many Related Tables

我有以下簡化的多對多相關模型:

public class Singer
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Song> Songs { get; set; }
}

public class Song
{
    [Key]
    public int Id { get; set; }

    public string Title { get; set; }

    public virtual ICollection<Singer> Singers { get; set; }
}

創建的數據庫表如下:

dbo.Singers
Id
Name

dbo.Songs
Id
Title

dbo.SingerSongs
Singer_Id
Song_Id

我使用以下種子代碼將項添加到已填充的表中,同時防止重復:

public static void SeedNewSingerAndSong(AppContext context)
{
    // Create new song
    Song newSong = new Song() { Title = "New Song" };

    context.Songs.AddOrUpdate(
        item => item.Title,
        newSong
    );

    context.SaveChanges();

    // Create new Singer
    Singer newSinger = new Singer() { Name = "New Singer" };

    context.Singers.AddOrUpdate(
        item => item.Name,
        newSinger
    );

    context.SaveChanges();
}

最近,我更新了種子代碼,將“新歌手”鏈接到“現有歌曲”和“新歌”,如下所示:

public static void SeedNewSingerAndSong(AppContext context)
{
    // Create new song
    Song newSong = new Song() { Title = "New Song" };

    context.Songs.AddOrUpdate(
        item => item.Title,
        newSong
    );

    context.SaveChanges();

    // Find existing songs
    Song foundExistingSong = context.Songs.Single(x => x.Title == "Existing Song");
    Song foundNewSong = context.Songs.Single(x => x.Title == "New Song");

    // Create new Singer
    Singer newSinger = new Singer() { Name = "New Singer" };

    // Assign songs to new Singer
    newSinger.Songs.Add(foundExistingSong);
    newSinger.Songs.Add(foundNewSong);

    context.Singers.AddOrUpdate(
        item => item.Name,
        newSinger
    );

    context.SaveChanges();
}

這不起作用(沒有添加關系)可能是因為之前已經添加了“New Singer”。 如果我手動刪除“新歌手”,歌手會在播種時加上關系。 但是,我不想刪除項目,因此我可以添加關系。 我如何使這個種子工作?

更新:播種前已經存在“新歌”時出現重復“新歌”的問題已使用更新的代碼修復。

為了提供更多背景信息, AddOrUpdate功能遠遠低於其名稱。

  1. 該方法查明實體是否存在。 如果沒有,則將其標記為已Added ; 如果是,則將其標記為已Modified 但是,雖然標記為已Added也將嵌套實體標記為已Added ,但標記為已Modified僅將實體本身標記為已Modified - 並且僅標記其標量屬性,即不標記其關聯。

  2. 它有一個惱人的錯誤 :如果找到現有實例,它會停止跟蹤代碼中可見的實例並開始跟蹤內部(不可見)實例。 代碼中對實例的任何后續更改都將被忽略

簡而言之:它適用於添加或更新隔離的實體,而不適用於相關實體。 我認為不可避免的結論是: 不要使用AddOrUpdate來播種相關實體

(就個人而言,我會更進一步,不使用它,期間)。

您還需要將歌手添加到歌曲中。 兩個列表Singer.Songs和Song.Singers都需要由您的代碼維護。

public static void SeedNewSingerAndSong(AppContext context)
{
    ...

    // Assign songs to new Singer
    newSinger.Songs.Add(foundExistingSong);
    newSinger.Songs.Add(foundNewSong);

    // Assign Singer to Songs
    foundExistingSong.Singers.Add(newSinger);
    foundfoundNewSong.Singers.Add(newSinger);

    // The following duplicates "New Song" as explained in *Additional Info
    context.Singers.AddOrUpdate(
        item => item.Name,
        newSinger
    );

    context.SaveChanges();
}

對於重復問題:

newSong未被實體框架跟蹤,因此與數據庫中的任何現有記錄無關。 當它被添加到newSinger時,它被視為新記錄並分配了新的id(主鍵)。 因此,你似乎得到了newSong的重復。

要修復,您需要跟蹤newSong,以便EF將其與其基礎記錄相關聯。 在這種情況下,您可以使用:

context.Attach(newSong)

通常,將跟蹤由查詢檢索的實體。 例如:

Song newSong = context.Songs.Single(x => x.Title == "New Song");

對於關系問題:

表明AddOrUpdate不更新關系。 一種解決方案是單獨更新關系,而另一種解決方案是明確說明所有添加的實體的主鍵值。 我懷疑后者也會刪除重復的問題。

你可以嘗試類似的東西:

var newSinger = context.Singers.Include("Songs").Single(x => x.Name == "New Singer");
newSinger.Songs.Clear();
newSinger.Songs = new List<Songs>{ foundNewSong, foundExistingSong };
context.SaveChanges();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM