0

Sorry for my bad English.

I have some class and EF Context generate from DB

1.Question

public int Id { get; set; }
public string Content { get; set; }

public virtual ICollection<Answer> Answer { get; set; }

2.Answer

public int Id { get; set; }
public string Content { get; set; }
public bool IsTrue { get; set; }

public virtual Question Question { get; set; }

All CRUD made through the Service. This is Update method for Question

public void Update(Question q)
{
   var editQuestion = GetById(q.Id); //get entity by id
   editQuestion.Answer = null;
   _repository.Update(editQuestion);

    q.Answer.Each(answer => answer.Question=editQuestion);

    editQuestion.Answer = q.Answer;
    editQuestion.Content = q.Content;

   _repository.Update(editQuestion);
   _unitOfWork.Commit();
}

_repository.Update(T Entity) =>

public virtual void Update(T entity)
{
   DbEntityEntry entityEntry = _context.Entry<T>(entity);
   entityEntry.State = EntityState.Modified;
}

Now in Db not update old Answer, but added new (q.Answer). In q.Answer may contains updated old Answer and some new.

How I can update Question?

UPD: _unitOfWork.Commit()

public void Commit()
{
   _context.SaveChanges();
}
ocuenca
  • 38,548
  • 11
  • 89
  • 102

1 Answers1

1

There is no need to play with the entry state. Simply get the entity by its Id, modify the relevant properties, remove old answers from the context, add the new ones to the collection, call SaveChanges() and it's job done.

Typically, one would write something like:

public void Update(Question q)
{
  using(var context = new MyDbContext())
  {
    var entity = context.Question.Find(q.Id);
    entity.Content = q.Content;

    foreach(var oldAnswer in entity.Answer)
    { 
      context.Answers.Remove(oldAnswer);
    }

    entity.Answer.Clear(); 

    foreach(var newAnswer in q.Answer)
    {
      entity.Answer.Add(newAnswer);
    }

    context.SaveChanges();
  } 
}

If you are not using the using pattern, don't forget to dispose the context at the end by calling context.Dispose().

Please note this is a solution where answer records would be deleted from the database and re-created even if they have not changed.

Alternatively, you could write a solution where existing records would be updated and only answers that no longer exist would be deleted:

public void Update(Question q)
{
  using(var context = new MyDbContext())
  {
    var entity = context.Question.Find(q.Id);
    entity.Content = q.Content;

    foreach(var newAnswer in q.Answer)
    {
      if (entity.Answer.All(a => a.Id != newAnswer.Id)
      {
        entity.Answer.Add(newAnswer);
      }
    }

    foreach(var oldAnswer in entity.Answer)
    { 
      if (q.Answer.All(a => a.Id != oldAnswer.Id)
      {
        context.Answers.Remove(oldAnswer);
      }
      else
      {
        var newAnswer = q.Answer.Single(a => a.Id == oldAnswer.Id);
        oldAnswer.Content = newAnswer.Content;
        oldAnswer.IsTrue = newAnswer.IsTrue;
      }
    }

    context.SaveChanges();
  } 
}
Alex Sanséau
  • 8,250
  • 5
  • 20
  • 25
  • In project i'm using Ninject and in UnitOfWork use injection in constructor. – Dzmitry Kharitonovich Jan 18 '15 at 21:21
  • DbContext bind like that ` Bind().To().InRequestScope();`. And no problem to save property non collection type. All problem started when i wan't update some collection. – Dzmitry Kharitonovich Jan 18 '15 at 21:30
  • I've updated my response to include update of Answer collection – Alex Sanséau Jan 18 '15 at 22:17
  • I totally agree with your [first point](http://stackoverflow.com/q/21758807/861716). The only thing is, according to the OP's code, you can simply remove the old answers and add the new ones. No need for these Id comparisons. – Gert Arnold Jan 18 '15 at 22:21
  • @GertArnold, this is not quite the same because records would be deleted from the database and then re-created - which could cause problem if transactions are not properly managed and/or if it had a column with creation date/time for instance. Anyway, I've updated my answer to offer both solutions. – Alex Sanséau Jan 19 '15 at 13:45