[英]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
功能遠遠低於其名稱。
該方法查明實體是否存在。 如果沒有,則將其標記為已Added
; 如果是,則將其標記為已Modified
。 但是,雖然標記為已Added
也將嵌套實體標記為已Added
,但標記為已Modified
僅將實體本身標記為已Modified
- 並且僅標記其標量屬性,即不標記其關聯。
它有一個惱人的錯誤 :如果找到現有實例,它會停止跟蹤代碼中可見的實例並開始跟蹤內部(不可見)實例。 代碼中對實例的任何后續更改都將被忽略 。
簡而言之:它適用於添加或更新隔離的實體,而不適用於相關實體。 我認為不可避免的結論是: 不要使用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.