将新记录添加到实体框架中—许多都有现有记录

本文关键字:许多 记录 添加 新记录 实体 框架 | 更新日期: 2023-09-27 18:00:12

我有两个类,如下所示:

public class Movie
{
    ...
    public virtual ICollection<Actor> Actors { get; set; }
}
public class Actor
{
    ...
    public virtual ICollection<Movie> Movies { get; set; }
}

实体框架在它们之间创建一个表来记录它们之间的关系。

现在,我的问题是如何在现有电影和唱片中添加新唱片?这个问题有两个部分:

  1. 使用以下方法,如何在不替换电影的所有现有关系的情况下将演员添加到电影中:

    public void AddRelationship(int movieId, int[] actorIds)
    {
        var movie = new Movie { Id = movieId };
        context.Movies.Attach(movie);
        foreach(var actorId in actorIds)
        {
            movie.Actors.add(new Actor{ Id = actorId });
        }
        context.SaveChanges();
    }
    

这创造了一个新的演员,这不是我想要的。

  1. 使用以下方法,我如何用给定的列表替换电影的所有演员:

    public void ReplaceRelationship(int movieId, int[] actorIds)
    {
    }
    

第二种方法的一种方法是删除所有现有的并读取它们,但我正在努力减少Db跳闸的数量。

此外,当添加时,我不想添加重复项,我是否必须在代码中找出所有关系并进行比较?

将新记录添加到实体框架中—许多都有现有记录

1.

当你这样做的时候,你实际上是在创造一个新的演员。

movie.Actors.add(new Actor{ Id = actorId });

你应该做的是首先附加现有的,然后添加它

var actor = new Actor{ Id = actorId };
context.Actors.Attach(actor);
movie.Actors.Add(actor);

或者完整的例子:

public void AddRelationship(int movieId, int[] actorIds)
{
    var movie = _context.Movies.FirstOrDefault(x => x.Id == movieId);
    // You might need to do include actors like this:
    //_context.Movies.Include(x => x.Actors).FirstOrDefault(x => x.Id = movieId);
    if(movie == null)
    {
        // Now what?
        throw new Exception("Invalid movieId");
    }
    foreach(var actorId in actorIds)
    {
        var actor = new Actor
        {
            Id = actorId
        };
        _context.Actors.Attach(actor);
        movie.Actors.Add(actor); // EF will detect if it already exists or not.
    }
    _context.SaveChanges();
}

2.

public void ReplaceRelationship(int movieId, int[] actorIds)
{
    var movie = _context.Movies.FirstOrDefault(x => x.Id = movieId);
    // You might need to do include actors like this:
    //_context.Movies.Include(x => x.Actors).FirstOrDefault(x => x.Id = movieId);
    if(movie == null)
    {
        // Now what?
        throw new Exception("Invalid movieId");
    }
    // Get a list of the already existing actors, so we know which to remove.
    var existingActorIds = movie.Actors.Select(x => x.Id).ToList();
    // Add new actors.
    foreach (var actorId in actorIds.Where(x => !existingActorIds .Contains(x.Id)))
    {
        var newActor = _context.Actors.Find(actorId );
       // You might be able to use this instead.
       // var newActor = new Actor { Id = actorId };
       // _context.Actors.Attach(newActor);
        movie.Actors.Add(newActor );
    }
    var idsToRemove =
        existingActorIds.Where(x => !actorIds.Contains(x));
    // Remove the old ones
    foreach (var actorId in idsToRemove)
    {
        var actorEntity = movie.Actors.FirstOrDefault(x => x.Id== actorId );
        // Again, you should be able to use Attach like above.
        // I use FirstOrDefault() since I actually need the full entity later.
        movie.Actors.Remove(actorEntity);
    }
    _context.SaveChanges();
}

第二种方法的一种方法是删除所有现有的读过了,但我正在努力减少Db的次数。

是的,我完全理解你。不幸的是,我没有找到比在每一个上实际调用Remove()更好的解决方案。

此外,当添加时,我不想添加重复项,我必须获得所有的关系都在我的代码中进行比较?

您可以先检查项目是否存在。但在我的情况下,EF为我管理了这一点。我的映射表有两个PK(一个用于MovieId,一个用于ActorId,这不允许重复。

    this.HasMany(t => t.Actors)
        .WithMany(t => t.Movies)
        .Map(m =>
        {
            m.ToTable("ActorMovies");
            m.MapLeftKey("ActorId");
            m.MapRightKey("MovieId");
        });