I am having a strange problem where a navigation property is not persisiting on the Update of a page, but is on a Create. I am using a Generic Repository pattern with Entity Framework 6, ASP.NET MVC 5.
Here's the skeleton code:
My context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection") { }
}
My repository implementation:
public class EntityFrameworkRepository : IRepository, IDisposable
{
private ApplicationDbContext _context;
private readonly ConcurrentDictionary<Type, object> _dbSets =
new ConcurrentDictionary<Type, object>();
public EntityFrameworkRepository(ApplicationDbContext context)
{
_context = context;
}
public void Save<T>(T entity) where T : BaseModel
{
GetDbSet<T>().Add(entity);
_context.SaveChanges();
}
public void Update<T> (T entity) where T: BaseModel
{
_context.Entry(entity).State = EntityState.Modified;
_context.SaveChanges();
}
}
Here the basis of Get of the Edit page uses AutoMapper to map between the domain model and the view model.
public ActionResult Edit(int menuId, int? id)
{
MenuItem mi = _repository.Get<MenuItem>((int)id);
Mapper.CreateMap<MenuItem, MenuItemViewModel>();
MenuItemViewModel mivm = Mapper.Map<MenuItem, MenuItemViewModel>(mi);
///....///
}
This is the method that is not working. As you can see, the full object UseSiblingClaim is being retrieved by id and set to the MenuItem itemToSave. I check the object just before _repository.Update() is called, and the property correctly.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int menuId, [Bind(Include = "Id,Name,ControllerName,ActionName,Order,CustomUrl,Tooltip,IconClass,CanUseParentsClaim,DoesNotNeedClaim,UseSiblingClaim_Id")] MenuItemViewModel mivm)
{
if (ModelState.IsValid)
{
mivm.Menu = _repository.Get<Menu>(menuId);
if (mivm.UseSiblingClaim_Id != null)
{
mivm.UseSiblingClaim = _repository.Get<MenuItem>((int)mivm.UseSiblingClaim_Id);
}
MenuItem itemToSave = MapViewModelToModel(mivm, _repository);
_repository.Update<MenuItem>(itemToSave);
return RedirectToAction("Details", "Menu", new { Id = menuId });
}
return View(mivm);
}
Here's the MenuItem class:
public class MenuItem : BaseModel
{
public MenuItem()
{
Children = new HashSet<MenuItem>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual MenuItem ParentMenuItem { get; set; }
public virtual Menu Menu { get; set; }
public string Name { get; set; }
///.....///
public virtual MenuItem UseSiblingClaim { get; set; }
}
The mapping method is here: UseSiblingClaim is being set.
private static MenuItem MapViewModelToModel(MenuItemViewModel mivm, IRepository _repository)
{
MenuItem itemToSave = new MenuItem()
{
UseSiblingClaim = mivm.UseSiblingClaim,
Id = mivm.Id,
ActionName = mivm.ActionName,
CanUseParentsClaim = mivm.CanUseParentsClaim,
ControllerName = mivm.ControllerName,
CustomURL = mivm.CustomURL,
DoesNotNeedClaim = mivm.DoesNotNeedClaim,
IconClass = mivm.IconClass,
Menu = mivm.Menu,
Name = mivm.Name,
Order = mivm.Order,
ParentMenuItem = mivm.ParentMenuItem,
Tooltip = mivm.Tooltip,
};
return itemToSave;
}
Here's the view model:
public class MenuItemViewModel : BaseModel
{
public int Id { get; set; }
public int ParentMenuItem_Id { get; set; }
public MenuItem ParentMenuItem { get; set; }
public int Menu_Id { get; set; }
public Menu Menu { get; set; }
public IEnumerable<SelectListItem> SiblingItems { get; set; }
[DisplayName("Can Use Sibling's Claim")]
public int? UseSiblingClaim_Id { get; set; }
public MenuItem UseSiblingClaim { get; set; }
}
The View part (this is the same for Create() and Update():
<div class="form-group">
@Html.LabelFor(model => model.UseSiblingClaim_Id, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(x => x.UseSiblingClaim_Id, Model.SiblingItems, new { @class = "select2", @multiple = "multiple", @style = "width:100%" })
@Html.ValidationMessageFor(model => model.UseSiblingClaim_Id)
</div>
</div>
Model.SiblingItems is created and passed into the view.
Why won't the UseSiblingClaim navigation property be persisted? It works on Create of the Menu Item, but not on Update? Is it something to do with me uaing a generic repositroy pattern? Please help