C# EF Seed多对多相关表
我有以下简化的多对多相关模型:C# EF Seed多对多相关表,c#,entity-framework,C#,Entity Framework,我有以下简化的多对多相关模型: 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 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; }
}
我使用以下种子代码将项添加到已填充的表中,同时防止重复:
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”,则在播种时该歌手将与关系一起添加。但是,我不想删除项目只是为了添加关系。我该如何让这个种子工作
更新:当“新歌”在播种之前已经存在时,重复“新歌”的问题已通过更新的代码修复。您还需要将歌手添加到歌曲中。这两个列表都列出了歌手。歌曲和歌曲。歌手需要由您的代码维护
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();
}
重复发行: 实体框架不会跟踪新闻歌曲,因此不会与数据库中的任何现有记录关联。当它被添加到newSinger时,它被视为一条新记录,并被分配了一个新id(主键)。因此,你似乎得到了新闻歌曲的副本 要修复此问题,您需要对newSong进行跟踪,以便EF将其与其基础记录相关联。在这种情况下,您可以使用:
context.Attach(新闻歌曲)
通常,将跟踪查询检索到的实体。e、 g:
Song newSong=context.Songs.Single(x=>x.Title==“新歌”)代码>
关于关系问题:
并指示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();
var newSinger=context.Singers.Include(“歌曲”).Single(x=>x.Name==“新歌手”);
newSinger.Songs.Clear();
newSinger.Songs=新列表{foundNewSong,foundExistingSong};
SaveChanges();
为了提供更多的背景信息,AddOrUpdate
所做的远远少于其名称所暗示的
该方法查明实体是否存在。如果未添加,则将其标记为添加的
;如果是,则将其标记为已修改
。但是,尽管标记为添加的也将嵌套实体标记为添加的,标记为修改的仅将实体本身标记为修改的,并且仅标记其标量属性,即不标记其关联
它有一个恼人的问题:如果它找到一个现有实例,它将停止跟踪代码中可见的实例,并开始跟踪内部(不可见)实例。代码中对实例的任何后续更改都将被忽略
简而言之:它适用于添加或更新独立实体,而不适用于相关实体。我认为不可避免的结论是:不要使用AddOrUpdate
来种子化相关实体
(就我个人而言,我会更进一步,不再使用它,句号)。你能发布DB模型吗?@Mikkk相关模型已经发布在顶部。底层表呢?你确定在调用AddOrUpdate(newSong)后会跟踪新闻歌曲吗?或者换句话说,是在调用AddOrUpdate(newSong)还是调用AddOrUpdate(newSinger)时创建的副本?是否可以确认跟踪是问题所在?您能否在将新闻歌曲添加到newSinger之前从数据库中检索新闻歌曲进行测试?@Mikkk非常感谢您的建议。一些显示如何最好地改进代码的代码会很有帮助。非常有意义。稍后我会尝试一下。为了澄清,我需要先添加或更新()没有相关歌曲的新歌手,然后再添加歌曲?但是为什么要使用Clear()?是的,添加或更新新歌手,然后添加歌曲。你是对的,不需要清除。我从其他代码中复制了这个示例,并在没有正确检查的情况下对其进行了修改。您可以使用“清除”保存创建新列表并添加项目。
var newSinger = context.Singers.Include("Songs").Single(x => x.Name == "New Singer");
newSinger.Songs.Clear();
newSinger.Songs = new List<Songs>{ foundNewSong, foundExistingSong };
context.SaveChanges();