title: ViewModels and one-to-many relationships with Entity Framework in MVC?
body: <p>I have an application for storing information about consultants in a database. The model is an Entity Framework model, and the database tables are Consultant with one-to-many relationships to a number of other tables (WorkExperiences, Programs, CompetenceAreas, etc). Now, when I want to create a new Consultant object in a View, I would really just want to pass a Consultant object as the model to the View. But for one, it has been suggested to me (<a href="https://stackoverflow.com/questions/5060817/collection-of-complex-child-objects-in-asp-net-mvc-3-application">Collection of complex child objects in Asp.Net MVC 3 application?</a>) that I shouldn't do this, but use ViewModels instead. Secondly, and maybe this is the reason, I get an error saying "The EntityCollection has already been initialized" when I try to post the Consultant object if using it as a model in the View, and the cause of the error seems to be the collections of objects such as WorkExperiences.</p>
  
  <p>So my first question is why I'm getting this error.</p>
  
  <p>But more importantly, if I should instead use a ViewModel, how would I do that properly? Because I have in fact tried something, and got it working. But...the code is awful. Can anyone please tell me what I should be doing instead to get this working more cleanly?</p>
  
  <p>Let me show you what I have (that again works, but is a nightmare codewise):</p>
  
  <p>The GET Create method:</p>
  
  <pre><code>    public ActionResult Create()
      {
          Consultant consultant = new Consultant();
          ConsultantViewModel vm = GetViewModel(consultant);
  
          return View(vm);
      }
  </code></pre>
  
  <p>Helper method to create the "ViewModel" (if this is in fact what a ViewModel is supposed to be like):</p>
  
  <pre><code>    private ConsultantViewModel GetViewModel(Consultant consultant)
      {
          ConsultantViewModel vm = new ConsultantViewModel();
          vm.FirstName = consultant.FirstName;
          vm.LastName = consultant.LastName;
          vm.UserName = consultant.UserName;
          vm.Description = consultant.Description;
  
          vm.Programs = consultant.Programs.ToList();
          vm.Languages = consultant.Languages.ToList();
          vm.Educations = consultant.Educations.ToList();
          vm.CompetenceAreas = consultant.CompetenceAreas.ToList();
          vm.WorkExperiences = consultant.WorkExperiences.ToList();
          return vm;
      }
  </code></pre>
  
  <p>The POST Create method:</p>
  
  <pre><code>    [HttpPost]
      [ValidateInput(false)] //To allow HTML in description box
      public ActionResult Create(ConsultantViewModel vm, FormCollection collection)
      {
          try
          {
              Consultant consultant = CreateConsultant(vm);
              _repository.AddConsultant(consultant);
              _repository.Save();
              return RedirectToAction("Index");
          }
          catch
          {
              return View();
          }
      }
  </code></pre>
  
  <p>Helper method to create a Consultant object (this one is particularly awful, where I have to check that collections are not null, in case the user decides not to add anything in those lists...):</p>
  
  <pre><code>    private Consultant CreateConsultant(ConsultantViewModel vm)
      {
          Consultant consultant = new Consultant();
          consultant.Description = vm.Description;
          consultant.FirstName = vm.FirstName;
          consultant.LastName = vm.LastName;
          consultant.UserName = vm.UserName;
  
          if (vm.Programs != null)
              foreach (var program in vm.Programs)
                  consultant.Programs.Add(program);
          if (vm.Languages != null)
              foreach (var language in vm.Languages)
                  consultant.Languages.Add(language);
          if (vm.Educations != null)
              foreach (var education in vm.Educations)
                  consultant.Educations.Add(education);
          if (vm.WorkExperiences != null)
              foreach (var workExperience in vm.WorkExperiences)
                  consultant.WorkExperiences.Add(workExperience);
          if (vm.CompetenceAreas != null)
              foreach (var competenceArea in vm.CompetenceAreas)
                  consultant.CompetenceAreas.Add(competenceArea);
  
          return consultant;
      }
  </code></pre>
  
  <p>So, again it works, but is nowhere near as clean as if I could have used a Consultant object directly (if not for that "EntityCollection is already initialized" error"...). So how should I do it instead?</p>