entity framework6插入重复值

我有以下两个实体:

public class Artist { [Key] public string ArtistId { get; set; } public string Name { get; set; } public virtual ICollection Genres { get; set; } } public class Genre { [Key] public int GenreId { get; set; } public string Name { get; set; } public virtual ICollection Artist { get; set; } } 

在我的程序中,我创建了一些艺术家,并希望保存它们:

 using (var context = new ArtistContext()) { var artists = _fullArtists.Select(x => x.Artist); foreach (var artist in artists) { context.Artists.AddOrUpdate(artist); } context.SaveChanges(); } 

entity framework正确创建了三个表:

艺术家(ArtistId,姓名)
类型(GenreId,姓名)
ArtistGenre(ArtistId,Gen​​reId)

但不幸的是,当我的艺术家样本数据看起来像这样:

 var a1 = new Artist { Name = "a1" }; a1.Genres.Add(new Genre { Name="rock"}); var a2 = new Artist { Name = "a2" }; a2.Genres.Add(new Genre { Name="rock"}); 

它将在表格Genre创建2条记录:

身份 名称
1块 石头
2 摇滚

而不是创建它一次然后重复使用它。

  • 您知道这是配置问题还是如何告诉EF不插入重复项并重用现有的?

提前致谢


编辑:不幸的是,谢尔盖别列佐夫斯基的解决方案不起作用(或者我可能做错了什么:D)

我现在拥有以下内容:

 using (var workUnit = WorkUnitFactory.CreateWorkUnit()) { var snapShot = new Snapshot { Date = DateTime.Now.Date }; //ICollection genres = _fullArtists.Select(x => x.ToArtist(snapShot)).SelectMany(x => x.Genres).Distinct(new GenreComparer()).ToList(); //workUnit.Repository().InsertEntities(genres); //workUnit.Commit(); var artists = _fullArtists.Select(x => x.ToArtist(snapShot)).ToList(); workUnit.Repository().InsertEntities(artists); workUnit.Commit(); } 

ArtistExtensions.cs

  public static class ArtistExtensions { public static Artist ToArtist(this FullArtistWrapper value, Snapshot snapShot) { if (value == null) { throw new ArgumentNullException(); } var artist = new Artist { ArtistId = value.Id, Name = value.Name }; var genres = value.Genres.Select(x => x.ToGenre()).ToList(); artist.Genres.AddRange(genres); return artist; } } 

GenreExtensions.cs

 public static class GenreExtensions { public static Genre ToGenre(this string value) { using (var workUnit = WorkUnitFactory.CreateWorkUnit()) { return workUnit.Repository().GetGenres().FirstOrDefault(x => x.Name == value) ?? new Genre {Name = value}; } } } 

不幸的是,EF仍在数据库中插入重复的Genres

InsertEntities(...)是这样的:

 public void InsertEntities(ICollection persistentEntitiesToBeInserted) where TPersistentEntity : PersistenceEntity { persistentEntitiesToBeInserted.ForEach(this.Add); } public void Add(PersistenceEntity entity) { var dbSet = this.Context.Set(entity.GetType()); dbSet.Add(entity); } 
  • 我是否误解了谢尔盖的答案,或者EF仍然会插入重复的另一个原因?

再次感谢

从EF的角度来看,如果两个实体指向数据库中的同一行,则它们是相同的。 即两个实体应具有相同的非零键。

如果您只想拥有一个名为“rock”的Genre实体,那么您应该将完全相同的类型实体添加到第二个艺术家类型集合中,或者您可以拥有两个实体,但它们应该具有相同的非零ID。 我想你有一些Add扩展方法可以创建新的类型并将其添加到艺术家的流派:

 public static void Add(this ICollection genres, string name) { genres.Add(new Genre { Name = name }); } 

每次调用此方法时,这将创建独立的类型实例。 因此,创建的实体的ID将等于零,EF将它们视为不同的实体。 例如

  a1.Genres.Add(new Genre { Name = "rock" }); a1.Genres.Add(new Genre { Name = "rock" }); 

在保存更改期间,EF将在流派集合中找到两个对象。 EF将检查实体ID并生成适当的SQL查询。 如果id为零,它将生成INSERT查询。 对于非零id,EF将生成UPDATE查询。 在这种情况下,您将有两个插入(稍微简化 – 请参阅下面的注释)。 如何解决? 您可以为两位艺术家使用完全相同的流派实体:

 var rock = new Genre { Name = "rock" }; var a1 = new Artist { Name = "a1" }; a1.Genres.Add(rock); var a2 = new Artist { Name = "a2" }; a2.Genres.Add(rock); 

如果您不想将新的’rock’行插入数据库,那么您可以使用现有的行而不是创建新的:

 var rock = db.Genres.FirstOrDefault(g => g.Name == "rock") ?? new Genre { Name = "rock" }; 

在您将Artist与Genre链接的类中,然后在代码中使用Name字段添加了2 Genre。

如果你做了,你会留在你的艺术家并添加2

 a1.Add("rock"); a1.Add("rock"); 

我认为有两种可能的原因不起作用:

  1. 您只需提交一次并在代码块的末尾。 因此,EF将所有类型添加为新类型。

  2. 您的基类PersistenceEntity可能不包含作为Key Id属性。 并且您的Add方法接受PersistenceEntity主类。 这可以将所有对象作为新对象。