使用现有记录

时间:2016-08-04 08:21:07

标签: c# entity-framework

我有两个课程如下:

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

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

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

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

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

    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();
    }
    
  2. 这会创建一个不是我想要的新Actor。

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

      public void ReplaceRelationship(int movieId, int[] actorIds)
      {
      
      }
      
    2. 使用第二种方法的方法是删除所有现有的并读取它们,但我试图保持Db的数量减少。

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

1 个答案:

答案 0 :(得分:0)

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