实体框架6插入重复值 [英] Entity Framework 6 inserting duplicate values

查看:62
本文介绍了实体框架6插入重复值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下两个实体:

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

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

In my program I create some artists and want to save them:

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 correctly created the three tables:

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

Artist (ArtistId, Name)
Genre (GenreId, Name)
ArtistGenre (ArtistId, GenreId)

但是不幸的是,当我的艺术家样本数据如下:

But unfortunately, when my artist sample data look like this:

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条记录:

It will create 2 records in table Genre:

Id 名称
岩石  
岩石  

IdName
rock   
rock   

而不是一次创建然后再使用它.

instead of creating it once and then reuse it.

  • 您知道这是一个配置问题还是如何告诉EF不要插入重复项,而是重复使用现有的?

预先感谢

不幸的是,谢尔盖·贝雷佐夫斯基(Sergey Berezovskiy)的解决方案不起作用(或者我做错了:D)

Unfortunately, the solution of Sergey Berezovskiy didn't work (or probably i did something wrong :D)

我现在所拥有的是以下内容:

What I have now is the following:

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();
}

ArtistExtensions.cs

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

GenreExtensions.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.

Unfortunately, EF still inserts duplicate Genres in the database.

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

  • 我是否误解了谢尔盖(Sergey)的答案,或者EF仍然插入重复项的另一个原因是什么?
  • 再次感谢

    推荐答案

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

    From EF point of view two entities are same if they are pointing to same row in database. I.e. two entities should have same non-zero keys.

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

    If you want to have only one Genre entity with name "rock", then you should add exactly same genre entity to second artist genres collection or you can have two entities, but they should have same non-zero ids. I suppose you have some Add extension method which creates new genre and adds it to artist's genres:

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

    这将在您每次调用此方法时创建独立的流派实例.因此,创建的实体的id将等于零,EF会将它们视为不同的实体.例如

    This will create independent instances of genres each time you call this method. Thus ids of created entities will be equal to zero, EF will treat them as different entities. E.g.

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

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

    During saving changes EF will find two objects in genres collection. EF will check entities ids and generate appropriate SQL queries. If id is zero, it will generate INSERT query. For non-zero id EF will generate UPDATE query. In this case you will have two inserts (a little simplified - see comment below). How to fix that? You can use exactly same genre entity for both artists:

    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);
    

    如果您不想在数据库中插入新的摇滚"行,则可以使用现有的而不是创建新的行:

    If you don't want to insert new 'rock' row to database, then you can use existing one instead of creating new:

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

    这篇关于实体框架6插入重复值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆