This question was probably asked in many forms before, but still I think that there is no clear solution to the scenario.
I have the following entity classes.
public class Project { public int ProjectId { get; set; } [Required(ErrorMessage="please enter name")] public string Name { get; set; } public string Url { get; set; } public DateTime CreatedOn { get; set; } public DateTime UpdatedOn { get; set; } public bool isFeatured { get; set; } public bool isDisabled { get; set; } public int GroupId { get; set; } public virtual Group Group { get; set; } [Required(ErrorMessage="Please select atleast one tag")] public virtual ICollection<Tag> Tags { get; set; } } public class Tag { public int TagId { get; set; } public string Name { get; set; } public DateTime CreatedOn { get; set; } public DateTime UpdatedOn { get; set; } public virtual ICollection<Project> Projects { get; set; } } public class Group { public int GroupId { get; set; } public string Name { get; set; } public DateTime CreatedOn { get; set; } public DateTime UpdatedOn { get; set; } public virtual ICollection<Project> Projects { get; set; } }
I have a viewmodel for a project object and a custom mediation for this model.
public class NewProjectModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { ProjectNewViewModel model = (ProjectNewViewModel)bindingContext.Model ?? (ProjectNewViewModel)DependencyResolver.Current.GetService(typeof(ProjectNewViewModel)); bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName); string searchPrefix = (hasPrefix) ? bindingContext.ModelName + ".":""; //since viewmodel contains custom types like project make sure project is not null and to pass key arround for value providers //use Project.Name even if your makrup dont have Project prefix model.Project = model.Project ?? new Project(); //populate the fields of the model if (GetValue(bindingContext, searchPrefix, "Project.ProjectId") != null) { model.Project.ProjectId = int.Parse(GetValue(bindingContext, searchPrefix, "Project.ProjectId")); } // model.Project.Name = GetValue(bindingContext, searchPrefix, "Project.Name"); model.Project.Url = GetValue(bindingContext, searchPrefix, "Project.Url"); model.Project.CreatedOn = DateTime.Now; model.Project.UpdatedOn = DateTime.Now; model.Project.isDisabled = GetCheckedValue(bindingContext, searchPrefix, "Project.isDisabled"); model.Project.isFeatured = GetCheckedValue(bindingContext, searchPrefix, "Project.isFeatured"); model.Project.GroupId = int.Parse(GetValue(bindingContext, searchPrefix, "Project.GroupId")); model.Project.Tags = new List<Tag>(); foreach (var tagid in GetValue(bindingContext, searchPrefix, "Project.Tags").Split(',')) { var tag = new Tag { TagId = int.Parse(tagid)}; model.Project.Tags.Add(tag); } var total = model.Project.Tags.Count; return model; } private string GetValue(ModelBindingContext context, string prefix, string key) { ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key); return vpr == null ? null : vpr.AttemptedValue; } private bool GetCheckedValue(ModelBindingContext context, string prefix, string key) { bool result = false; ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key); if (vpr != null) { result = (bool)vpr.ConvertTo(typeof(bool)); } return result; } } //My project controller edit action defined as under: [HttpPost] [ActionName("Edit")] public ActionResult EditProject( ProjectNewViewModel ProjectVM) { if (ModelState.IsValid) { projectRepository.InsertOrUpdate(ProjectVM.Project); projectRepository.Save(); return RedirectToAction("Index"); } else { ViewBag.PossibleGroups = groupRepository.All; return View(); } } //Group Repository public void InsertOrUpdate(Project project) { if (project.ProjectId == default(int)) { // New entity foreach (var tag in project.Tags) { context.Entry(tag).State = EntityState.Unchanged; } context.Projects.Add(project); } else { context.Entry(project).State = EntityState.Modified; } }
Now that I have a project inside the editing view, and I select new tags for the project and present a form editing action parameter, use the model binding and set all the properties of the project object, including tags. But when the project object is passed to the insertorupdate grouprepository method, all the changes we made go to the database, except for the tag collection property, now I'm really upset about this thing.
Please provide me with a solution that would not introduce changes to the structure that have been developed so far.