EF4.3 MVC 4 Ninject CustomModelBinderAttribute для абстрактного базового класса, теряющего значения записей - PullRequest
2 голосов
/ 01 апреля 2012

Я постараюсь объяснить, как могу ... Огромный пост, потому что я не на 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">&nbsp;</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", и прикрепить его обратно к объекту, прежде чем возвращать его в представление, но я думаю, что это будет ужасная практика.

Есть идеи?

...