插入重复值的实体框架 6

本文关键字:实体 框架 插入 | 更新日期: 2023-09-27 18:32:47

我有以下两个实体:

public class Artist
{
    [Key]
    public string ArtistId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Genre> Genres { get; set; }
}
public class Genre
{
    [Key]
    public int GenreId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Artist> 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();
}

实体框架正确创建了三个表:

Artist

(ArtistId, Name(
流派(流派 ID,名称(
ArtistGenre (ArtistId, GenreId(

但不幸的是,当我的艺术家示例数据如下所示时:

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<Genre> genres = _fullArtists.Select(x => x.ToArtist(snapShot)).SelectMany(x => x.Genres).Distinct(new GenreComparer()).ToList();
     //workUnit.Repository<IGenreRepository>().InsertEntities(genres);
     //workUnit.Commit();
     var artists = _fullArtists.Select(x => x.ToArtist(snapShot)).ToList();
     workUnit.Repository<IArtistRepository>().InsertEntities(artists);
     workUnit.Commit();
}

艺术家扩展.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;
        }
    }

流派扩展.cs

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

遗憾的是,EF 仍在数据库中插入重复的Genres

InsertEntities(...)是这样的:

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

再次感谢

插入重复值的实体框架 6

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

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

public static void Add(this ICollection<Genre> 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 将生成更新查询。在这种情况下,您将有两个插入(稍微简化 - 请参阅下面的评论(。如何解决?您可以为两位艺术家使用完全相同的流派实体:

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" };

在类中,您将艺术家链接到流派,然后在代码中使用名称字段添加了 2 流派。

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

a1.Add("rock");
a1.Add("rock");
我认为有两个

可能的原因不起作用:

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

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