I will try to explain as best i can... Huge post coming as i'm not 100% where the problem lies. It probably has a really simple fix but i'm pulling hair at the min.
I have an abstract base class with a navigation property to a document type like so
public abstract class Document: Identity
{
public int DocumentTypeId { get; set; } // this remains and alls good
public virtual DocumentType DocumentType { get; set; } // this dissappears.
}
This DocumentType object contains a string value for the namespace for the type of object that it is. As an example I then have a class derived the document abstract class like so
public class Blog : Document
{
//properties excluded to keep this post from being HUGE!
}
They all have properties which are saving back to the database. however the document type is missing. Not the DocumentTypeId, that is there, but the actual DocumentType, I need to navigate into it to get the namespace value but it is missing.
It now gets a bit more complicated. I am using a ninject generic repository that injects, in this case the Blog into the view. Here is an example controller.
public class ContentController : Controller
{
private IRepository<Document> repo;
public ContentController(IRepository<Document> _repo)
{
repo = _repo;
}
public ActionResult Settings(string name) //name is unique!
{
Document d = repo.First(x => x.Name == name);
return View(d); // all properties are present
}
[HttpPost]
public ActionResult Settings([AbstractBind()] Document obj)
{
repo.Save(obj); // documenttype is missing documenttypeId is present.
return View(obj);
// this does not work but refresh does?!
//Document d = repo.First(x => x.Name == obj.name);
//return View(d);
}
}
because the view is bound to an abstract class I am using the editor for model like so
@model Core.Entities.Documents.Abstract.Document
@{
ViewBag.Title = "Index";
Layout = "~/Areas/Admin/Views/Shared/_CMSContent.cshtml";
}
<h2>Settings - @Model.Name</h2>
@using (Html.BeginForm())
{
@Html.Hidden("Namespace", Model.DocumentType.Namespace);
@Html.ValidationSummary(true)
@Html.EditorForModel();
<div class="editor-label"> </div>
<div class="editor-field">
<input type="submit" value="Save" class="btn" />
</div>
<br class="clear" />
@Html.ActionLink("< Back to List", "Index")
}
Notice that i am adding a hidden field for the namespace contained within the view. Also notice that i am using a custom binding method to figure out what type is actually being edited, by going through the following method:
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var type = Assembly.GetAssembly(typeof(Document)).GetType(bindingContext.ValueProvider.GetValue("Namespace").AttemptedValue);
var model = Activator.CreateInstance(type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
return model;
}
this figures out what type it is, (Blog). How do i get the DocumentType reference back into my model on the HTTP post?
I have tried adding a hidden field for the type like this @Html.HiddenFor(x => x.DocumentType); but it doesn't work.
I also tried going and getting it from the repository again after saving (commented out in the example) but no joy. If i refresh the page then the field is back again as Ninject and EF figures out that the Id is a foreign key that points to the DocumentType.
I could go and get the document type by the id that is in the "Document obj" and attach it back to the object before returing it to the view but i think that this would be terrible practise.
Any ideas?