0

I have two API calls. GetExam and SaveExam. GetExam serializes to JSON which means by the time I go to save, the entity is detached. This isnt a problem, I can go retrieve the entity by its primary key and update its properties manually.

However, when I do so the exam questions get its current collection duplicated. For example, if examToSave.ExamQuestions had a few questions deleted, and a new one added all selectedExam.exam_question are duplicated and the new one is added in. Eg. if 3 questions existed, I deleted 1 and added 4 there will now be 7.

Domain models:

public partial class exam
{
    public exam()
    {
        this.exam_question = new HashSet<exam_question>();
    }

    public int ID { get; set; }
    public string ExamName { get; set; }
    public string ExamDesc { get; set; }
    public Nullable<decimal> TimeToComplete { get; set; }
    public bool AllowBackStep { get; set; }
    public bool RandomizeAnswerOrder { get; set; }
    public int Attempts { get; set; }

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

public partial class exam_question
{
    public exam_question()
    {
        this.exam_answer = new HashSet<exam_answer>();
    }

    public int ID { get; set; }
    public int ExamID { get; set; }
    public string QuestionText { get; set; }
    public bool IsFreeForm { get; set; }

    public virtual exam exam { get; set; }
    public virtual ICollection<exam_answer> exam_answer { get; set; }
}

public partial class exam_answer
{
    public int ID { get; set; }
    public string AnswerText { get; set; }
    public int QuestionID { get; set; }
    public bool IsCorrect { get; set; }

    public virtual exam_question exam_question { get; set; }
}

Save method:

[Route("SaveExam")]
[HttpPost]
public IHttpActionResult SaveExam(ExamViewModel examToSave)
{
    using (var db = new IntranetEntities())
    {
        // try to locate the desired exam to update
        var selectedExam = db.exams.Where(w => w.ID == examToSave.ID).SingleOrDefault();

        if (selectedExam == null)
        {
            return NotFound();
        }

        // Redacted business logic

        // Map the viewmodel to the domain model
        Mapper.CreateMap<ExamAnswerViewModel, exam_answer>();
        Mapper.CreateMap<ExamQuestionViewModel, exam_question>().ForMember(dest => dest.exam_answer, opt => opt.MapFrom(src => src.QuestionAnswers));
        Mapper.CreateMap<ExamViewModel, exam>().ForMember(dest => dest.exam_question, opt => opt.MapFrom(src => src.ExamQuestions));
        var viewmodel = Mapper.Map<exam>(examToSave);

        // Update exam properties
        selectedExam.ExamName = viewmodel.ExamName;
        selectedExam.ExamDesc = viewmodel.ExamDesc;
        selectedExam.AllowBackStep = viewmodel.AllowBackStep;
        selectedExam.Attempts = viewmodel.Attempts;
        selectedExam.RandomizeAnswerOrder = viewmodel.RandomizeAnswerOrder;
        selectedExam.exam_question = viewmodel.exam_question; // DUPLICATES PROPS

        // Save 
        db.SaveChanges();

        return Ok(examToSave);
    }

}
Yuliam Chandra
  • 13,858
  • 12
  • 49
  • 66
Victorio Berra
  • 2,077
  • 2
  • 20
  • 37
  • I'm afraid assigning collection from viewmodel to ef entity (`selectedExam.exam_question = viewmodel.exam_question;`) is not the right way, you need to **1.** find which ones from `selectedExam.exam_question` that are not found in `viewmodel.exam_collection`, then remove them **2.** find which ones from `viewmodel.exam_collection` that are not found in `selectedExam.exam_question`, then add them – Yuliam Chandra Sep 30 '14 at 15:27
  • That approach seems easier, but it doesn't help with the questions that have changed, or had thier answers changed. So how do you feel about this? http://pastie.org/private/cuhgrldgzvhebzv529aea – Victorio Berra Sep 30 '14 at 15:30
  • probably something like [this](http://stackoverflow.com/a/7969372) – Yuliam Chandra Sep 30 '14 at 15:36
  • I will say that does seem like the correct way to go through each individual property and create/update/delete after checking each one. But its hard to do when its so painless and simple to just dump and re-populate the collection. – Victorio Berra Sep 30 '14 at 15:42
  • 1
    You're not alone, see this [bounty question](http://stackoverflow.com/questions/26072646/has-ef6-7-added-any-ways-that-i-can-add-update-child-tables) and see the comment that relates to user voice, looking for elegant solution? you might want to use [graphdiff](http://blog.brentmckendrick.com/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/) – Yuliam Chandra Sep 30 '14 at 15:44
  • Its good to hear I am not alone. It seems like this should be a common feature I bet we will see something implemented with all the vNext stuff. Thanks. – Victorio Berra Sep 30 '14 at 15:53

0 Answers0