Создайте раскрывающийся список для MVC3 с использованием Entity Framework (.edmx Model) и Razor Views && Вставьте запись базы данных в несколько таблиц
После прочтения 100 статей о том, как создать список DropDown в MVC 3 с помощью Razor Views, я не смог найти тот, который соответствует моему делу. Поэтому после часов и часов поиска ответа я решил опубликовать этот вопрос, чтобы узнать, есть ли у кого ответ или может помочь мне. Спасибо заранее!
Ситуация:
В конечном итоге я пытаюсь создать представление для добавления сотрудника в базу данных.
Вот образ используемой мной модели .EDMX(таблицы, которые будут использоваться create().):
![enter image description here]()
Задачи:
-
Создайте сотрудника (у меня есть Create.cshtml(строго типизированный), сделанный с частичным представлением для флажков StaffNotify) {Я использую отдельный @model в Notify Partial View из Create View, но не уверен, что это безопасно??? @model ShadowVenue.Models.Employee и @model ShadowVenue.Models.StaffNotify)
-
Создайте окно Dropdown для StaffTypeId (которое будет вставлять значение [StaffTypeId] из таблицы "StaffType" (с отношением от 1 до многих), но отображает строковое значение [Type] в раскрывающемся списке)
-
Создайте раскрывающийся список для GenderId (который будет вставлять значение [GenderId] из таблицы "Genders" (с отношением от 1 до многих), но будет показывать значение строки [Gender] в раскрывающемся списке)
-
Вставьте запись в базу данных (у меня есть уведомления о сотрудниках в отдельной таблице с отношением 1 к 1 на первичный ключ StaffId)
Кажется, у меня проблемы с кодом контроллера для этого.
Я не уверен, что я должен создать Хранимую процедуру в модели EDMX или придумать синтаксис запроса или метода, но не уверен, что это лучший способ.
Это мое первое большое приложение MVC3, использующее модель платформы Entity.
Спасибо за ваше время. Я действительно ценю знающих пользователей на этом сайте.
(если вам нужно знать какие-либо из названий навигационных свойств, чтобы помочь с решением, просто сообщите мне, я предоставит их вам)
Ответы
Ответ 1
Не переходите модели db непосредственно к вашим представлениям. Вам повезло, что вы используете MVC, поэтому инкапсулируйте с помощью моделей представлений.
Создайте класс модели представления следующим образом:
public class EmployeeAddViewModel
{
public Employee employee { get; set; }
public Dictionary<int, string> staffTypes { get; set; }
// really? a 1-to-many for genders
public Dictionary<int, string> genderTypes { get; set; }
public EmployeeAddViewModel() { }
public EmployeeAddViewModel(int id)
{
employee = someEntityContext.Employees
.Where(e => e.ID == id).SingleOrDefault();
// instantiate your dictionaries
foreach(var staffType in someEntityContext.StaffTypes)
{
staffTypes.Add(staffType.ID, staffType.Type);
}
// repeat similar loop for gender types
}
}
Контроллер:
[HttpGet]
public ActionResult Add()
{
return View(new EmployeeAddViewModel());
}
[HttpPost]
public ActionResult Add(EmployeeAddViewModel vm)
{
if(ModelState.IsValid)
{
Employee.Add(vm.Employee);
return View("Index"); // or wherever you go after successful add
}
return View(vm);
}
Затем, наконец, в вашем представлении (которое вы можете сначала использовать Visual Studio для его эшафот), измените унаследованный тип на ShadowVenue.Models.EmployeeAddViewModel. Кроме того, когда выпадающие списки идут, используйте:
@Html.DropDownListFor(model => model.employee.staffTypeID,
new SelectList(model.staffTypes, "ID", "Type"))
и аналогичным образом для раскрывающегося списка gender
@Html.DropDownListFor(model => model.employee.genderID,
new SelectList(model.genderTypes, "ID", "Gender"))
Обновление для комментариев
Для пола вы также можете сделать это, если вы можете быть без гендерных типов в предложенной выше модели представления (хотя, с другой стороны, возможно, я бы сгенерировал эту серверную часть в модели представления как IEnumerable). Итак, вместо new SelectList...
ниже вы должны использовать свой IEnumerable.
@Html.DropDownListFor(model => model.employee.genderID,
new SelectList(new SelectList()
{
new { ID = 1, Gender = "Male" },
new { ID = 2, Gender = "Female" }
}, "ID", "Gender"))
Наконец, другой вариант - таблица Lookup. В принципе, вы сохраняете пары ключ-значение, связанные с типом поиска. Одним из примеров типа может быть пол, в то время как другой может быть государством и т.д. Мне нравится структурировать мои как это:
ID | LookupType | LookupKey | LookupValue | LookupDescription | Active
1 | Gender | 1 | Male | male gender | 1
2 | State | 50 | Hawaii | 50th state | 1
3 | Gender | 2 | Female | female gender | 1
4 | State | 49 | Alaska | 49th state | 1
5 | OrderType | 1 | Web | online order | 1
Мне нравится использовать эти таблицы, когда набор данных не меняется очень часто, но все же нужно время от времени перечислять.
Надеюсь, это поможет!
Ответ 2
Ну, на самом деле я должен буду сказать, что Дэвид прав с его решением, но меня беспокоят некоторые темы:
- Вы никогда не должны отправлять свою модель в представление = > Это правильно
- Если вы создаете
ViewModel
и включаете элемент Model как член в ViewModel
, вы фактически отправили свою модель в представление = > , это BAD
- Использование словарей для отправки параметров в представление = > этот нехороший стиль
Итак, как вы можете создать лучшее соединение?
Я использовал бы инструмент, например AutoMapper
или ValueInjecter, чтобы сопоставить между ViewModel
и Model.
AutoMapper
похоже, имеет лучший синтаксис и чувствует к нему, но в текущей версии отсутствует
очень серьезная тема: он не может выполнить сопоставление от ViewModel
до модели (при определенных обстоятельствах, таких как сплющивание и т.д., но это не в тему)
Поэтому в настоящее время я предпочитаю использовать ValueInjecter
.
Итак, вы создаете ViewModel
с полями, которые вам нужны в представлении.
Вы добавляете элементы SelectList, которые вам нужны для поиска.
И вы добавляете их как SelectLists уже. Таким образом, вы можете запрашивать данные из LINK с поддержкой sourc, выбирать идентификатор и текстовое поле и сохранять его как список избранных:
Вы получаете то, что вам не нужно создавать новый тип (словарь) в качестве поиска, и вы просто перемещаете new SelectList
из представления в контроллер.
// StaffTypes is an IEnumerable<StaffType> from dbContext
// viewModel is the viewModel initialized to copy content of Model Employee
// viewModel.StaffTypes is of type SelectList
viewModel.StaffTypes =
new SelectList(
StaffTypes.OrderBy( item => item.Name )
"StaffTypeID",
"Type",
viewModel.StaffTypeID
);
В представлении вам просто нужно позвонить
@Html.DropDownListFor( model => mode.StaffTypeID, model.StaffTypes )
В элементе post вашего метода в контроллере вы должны взять параметр типа ViewModel
. Затем вы проверяете подтверждение.
Если проверка не удалась, вы должны помнить о повторном заполнении viewModel.StaffTypes
SelectList, потому что этот элемент будет пустым при вводе функции post.
Поэтому я склоняюсь к тому, что эти вещи населения разделяются на функцию.
Вы просто вызываете return new View(viewModel)
, если что-то не так.
Ошибки проверки, найденные MVC3, будут автоматически отображаться в представлении.
Если у вас есть собственный код проверки, вы можете добавить ошибки проверки, указав, к какому полю они принадлежат. Проверьте документацию на ModelState
, чтобы получить информацию об этом.
Если ViewModel
действителен, вам необходимо выполнить следующий шаг:
Если это создание нового элемента, вам нужно заполнить модель из ViewModel
(наиболее подходящим является ValueInjecter
). Затем вы можете добавить его в коллекцию EF этого типа и зафиксировать изменения.
Если у вас есть обновление, вы сначала получаете текущий элемент db в модель. Затем вы можете скопировать значения из ViewModel
обратно в модель (опять же, используя ValueInjecter
, вы делаете это очень быстро).
После этого вы можете SaveChanges
и закончите.
Не стесняйтесь спрашивать, что-то неясно.