Обзорамногоразовый MVC кода: обработка типы значений в LINQ выражение
Я пишу набор MVC, который предназначен для обеспечения основного поиска/добавлять/редактировать/удалять функции для объекта Entity Framework. Он также выполняет некоторые причудливые вещи, такие как поддержка выпадающих списков, заполненных из других таблиц с использованием атрибутов.
Основной задачей в игре является наследуемым общий контроллер (AdminController<T>
, где T
является объектом EF), содержащий массив AdminField<T>
, каждый элемент которого представляет собой поле/свойство в T
. AdminController<T>
может сгенерировать объект AdminViewModel<T>
. Ниже представлена диаграмма Visio отношений между этими объектами.
Проблема
Моя проблема заключается в соображениях. Чтобы отображать значения, я использую помощники Html.EditorFor
/HiddenFor
/TextboxFor
. Гипер-упрощенное представление просто пересекает поле и отображает их значения, позволяя редактировать, если они являются редактируемыми полями. Это выглядит следующим образом:
@model AdminViewModel<ExampleEFObject>
@using (Html.BeginForm())
{
foreach (var f in Model.Fields)
{
var expression = Model.ExpressionFromField(f);
<label class="control-label col-md-3">@f.DisplayName</label>
@if (!f.Editable)
{
@Html.TextBoxFor(expression, new { @class = "form-control", @disabled = "disabled" })
}
else
{
@Html.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" } })
}
}
<input type="submit" value="Save" class="btn btn-primary" />
}
Ну, вот что я хочу это выглядеть. Он отлично работает с полями/свойствами, которые являются ссылочными типами. С типами значений, однако, я получаю System.InvalidOperationException
ошибку на EditorFor
линии: «Шаблоны могут быть использованы только с доступом поля, доступ к собственности, одномерный индекс массива или одного параметра выражений пользовательских индексатор.»
Это связано с тем, что метод ExpressionFromField
, который возвращает выражение, обращающееся к экземпляру T
в ViewModel, имеет тип возврата Expression<Func<AdminViewModel<T>, object>>
. Поскольку он возвращает тип объекта, бокс принудительно генерирует выражение, так что вместо (например) t => t.Count
мой метод фактически возвращает t => Convert(t.Count)
.
Текущий Обход
Мой текущий обходной путь, чтобы иметь второй метод, определенный в качестве Expression<Func<AdminViewModel<T>, int>> IntExpressionFromField(AdminField<T> field)
. Поскольку он возвращает int
, он не форсирует бокс в выражении. Тем не менее, это делает мои взгляды крайне некрасиво:
@model AdminViewModel<ExampleEFObject>
@using (Html.BeginForm())
{
foreach (var f in Model.Fields)
{
var expression = Model.ExpressionFromField(f);
var intExpression = Model.IntExpressionFromField(f);
<label class="control-label col-md-3">@f.DisplayName</label>
@if (!f.Editable)
{
if (intExpression == null)
{
@Html.TextBoxFor(expression, new { @class = "form-control", @disabled = "disabled" })
}
else
{
@Html.TextBoxFor(intExpression, new { @class = "form-control", @disabled = "disabled" })
}
}
else
{
if (intExpression == null)
{
@Html.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" } })
}
else
{
@Html.EditorFor(intExpression, new { htmlAttributes = new { @class = "form-control" } })
}
}
}
<input type="submit" value="Save" class="btn btn-primary" />
}
Хуже того, это поддерживает только 1 тип значения (int
). Я также хотел бы поддерживать десятичное, длинное и все остальное - желательно без необходимости создавать собственные методы для каждого, а также всю логику для защиты от других типов.
Помощь!
Я хотел бы найти элегантный и простой способ решить эту проблему. Если ни один из них не существует, я думаю, что моим следующим шагом было бы прекратить использование вспомогательных методов Html
; однако это потребует нарушения согласованности с остальной частью приложения, и я даже не знаю, что это решит проблему.
Любая помощь была бы высоко оценена!
В общем, плохая практика передачи вашего объекта EF для просмотра. Вам, вероятно, придется создать абстрактную форму FormViewModel, которая содержит реализации некоторых абстрактных FieldViewModels (с шаблонами редакторов, такими как DatePickerViewModel, TextBoxViewModel и т. Д.), А в вашем контроллере вам необходимо преобразовать эту модель представления для обновления операций для объекта Entity Framework или в DTO, если у вас есть сервисный уровень. –
В целом это не стоит того, что не позволяет выполнять сложные макеты или причудливое взаимодействие с пользователем, поэтому переход на ViewModels и ручной код для обновления объектов жизнеспособен, если у вас не так много объектов –
@raderick: Спасибо за отвечать на запросы. Я не передал свой объект EF в представление, а только общий ViewModel. Однако, если это плохая практика, мне бы хотелось понять, почему я могу выбрать лучший подход в будущем. Причина, по которой я делаю это, состоит в том, что существуют десятки типов объектов, для которых требуются только некоторые основные функции обслуживания. Я хочу, чтобы не было десятков одинаковых наборов MVC. Подход, который вы описали, кажется невероятно тяжелым и ограниченным, как вы сказали, но я буду помнить его в качестве резервного варианта. – Daniel