Я постараюсь объяснить, как могу ... Огромный пост, потому что я не на 100% в том, в чем проблема. Вероятно, это действительно очень легко исправить, но я дергаю волосы в мин.
У меня есть абстрактный базовый класс со свойством навигации по типу документа, например
public abstract class Document: Identity
{
public int DocumentTypeId { get; set; } // this remains and alls good
public virtual DocumentType DocumentType { get; set; } // this dissappears.
}
Этот объект DocumentType содержит строковое значение для пространства имен для типа объекта, которым он является. Например, у меня есть класс, выведенный из абстрактного класса документа, например:
public class Blog : Document
{
//properties excluded to keep this post from being HUGE!
}
Все они имеют свойства, которые сохраняются обратно в базу данных. однако тип документа отсутствует. Не DocumentTypeId, который там есть, а фактический DocumentType, мне нужно перейти к нему, чтобы получить значение пространства имен, но оно отсутствует.
Теперь все немного сложнее. Я использую универсальный репозиторий, который внедряет, в данном случае, блог в представление. Вот пример контроллера.
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);
}
}
поскольку представление привязано к абстрактному классу, я использую редактор для модели, например, так:
@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")
}
Обратите внимание, что я добавляю скрытое поле для пространства имен, содержащегося в представлении. Также обратите внимание, что я использую пользовательский метод привязки, чтобы выяснить, какой тип на самом деле редактируется, выполнив следующий метод:
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;
}
это выясняет, к какому типу это относится (блог). Как мне вернуть ссылку DocumentType в мою модель в сообщении HTTP?
Я попытался добавить скрытое поле для типа, подобного этому @ Html.HiddenFor (x => x.DocumentType); но это не работает
Я также попытался пойти и получить его из хранилища снова после сохранения (закомментировано в примере), но без радости. Если я обновлю страницу, то поле снова вернется, поскольку Ninject и EF выяснят, что Id - это внешний ключ, который указывает на DocumentType.
Я мог бы пойти и получить тип документа по идентификатору, который находится в "Document obj", и прикрепить его обратно к объекту, прежде чем возвращать его в представление, но я думаю, что это будет ужасная практика.
Есть идеи?