Как правильно сохранить отношения многие ко многим в Entity Framework - PullRequest
0 голосов
/ 07 июня 2011

В настоящее время я работаю со следующей первой моделью кода EF, которая имеет отношение многие ко многим между человеком и тегом.

public class person
{
   public Person()
   {
      this.Tags = new List<Tag>();
   }

   public int Id { get; set; }
   public string Name { get; set; }
   public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
   public Tag()
   {
      this.People = new List<Person>();
   }

   public int Id { get; set; }
   public string Name { get; set; }
   public virtual ICollection<Person> People { get; set; }
}

public MyContext : DbContext
{
   public DbSet<Person> People { get; set; }
   public DbSet<Tag> Tags { get; set; }
}

Затем я передаю модель Json контроллеру MVC, которыйсодержит существующего человека и обновляет имя человека, а также добавляет или удаляет теги из списка тегов этого человека.

У меня были некоторые проблемы с правильной привязкой тегов к человеку.После долгих проб и ошибок, я пришел к следующему методу, который работает:

[HttpPost]
public JsonResult Save(Person person)
{
   //get ids of all tags that are associated with this person.
   var tagIds = new List<int>();
   foreach (var tag in person.Tags)
   {
      tagsIds.Add(tag.Id);
   }

   //clone the person minus the tags
   var personToSave = person;
   personToSave.Tags = new List<Tag>();

   var context = new MyContext();
   var existingTags = (from t in context.Tags
                       where t.People.Count > 0 && t.People.All(p => p.Id == person.Id)
                       select t).ToList();

   //attach the person, so updates to the person object will save.
   context.Entry(personToSave).State = EntityState.Modified;

   if (tagIds.Count > 0)
   {
      //add new tags
      var tags = context.Tags.Where(t => tagIds.Contains(t.Id));
      foreach (var tag in tags)
      {
         //check if tags has no people and not already associated to this person.
         if (tag.People.Count == 0 || tag.People.First(p => p.Id == person.Id) == null)
         {
             personToSave.Tags.Add(tag);
         }
      }

     //remove tags that exist for this person, but were not specified in the list of
     //tags on the person object that was passed into the method.
     foreach(var existingTag in existingTags)
     {
          if (!tagIds.Contains(existingTag.Id)
          {
              context.Tags.Find(existingTag.Id).People.Remove(person);
          }
     }         
   }

   //Finally if no tags were passed in the model and the person has tags, remove them.
   if (tagsIds.Count == 0 && existingTags.Count > 0)
   {
       foreach (var oldTag in existingTags)
       {
           context.Tags.Find(oldTag.Id).People.Remove(person);
       }
   }

   context.SaveChanges();

   var message = string.Format("Saved {0} with {1} tags", person.Name, person.Tags.Count);
   return Json(new {message});

}

Весь этот код выглядит как большая работа по добавлению / удалению тегов у человека.Я все еще довольно новичок в Entity Framework, поэтому я чувствую, что, возможно, что-то упустил.Я хотел бы знать, есть ли у меня лучший способ сделать это.Кроме того, обратите внимание, что это было первое, что я смог получить на работе, так что, возможно, есть дополнительные рефакторинги, которые можно применить.

...