Как использовать раскрывающиеся списки в ASP.NET MVC со значениями поиска без ViewBag?

Это должно быть очень легко, и я не могу в жизни понять, что я не нашел ответов на этот вопрос, несмотря на, по крайней мере, час поиска в Google. Во всяком случае, здесь мы идем:

Я хочу создать простое представление ASP.NET MVC с некоторыми раскрывающимися списками, которые позволяют пользователю выбирать некоторые значения, которые затем сохраняются как идентификаторы в базе данных. Поскольку мне сказали, что ViewBag/ViewData - это дьявольская работа, я попытался решить эту проблему, добавив список выбора в мою модель (View), например:

public virtual SelectList Accommodations { get; set; }

а затем в моем контроллере заполните его чем-то вроде:

LoanApplication theLoanApplication = new LoanApplication();
            theLoanApplication.Accommodations = new SelectList(db.Accommodations.ToList(), "AccommodationID", "Name");

и, наконец, на мой взгляд, используйте это, чтобы все заработало:

@Html.DropDownListFor(model => model.AccommodationID, Model.Accommodations, "Choose Accommodation")

Это работает так, как должно, но когда я пытаюсь сохранить модель, я получаю сообщение об ошибке, что свойство Accommodations (список) имеет значение null, что вполне ожидаемо. Все остальное в моей модели, как и должно быть.

Я просмотрел хорошо известный пример кода «Университет графства» на сайте ASP.NET, и в нем они, похоже, используют ViewBag для решения подобных проблем. Значит ли это, что ViewBag не так уж плох для использования в подобном сценарии и может быть даже лучшим возможным решением? Если нет, то какой предпочтительный способ решить эту проблему и не использовать ViewBag/ViewData?

Спасибо.


person ImproWise    schedule 13.06.2015    source источник
comment
покажи код контроллера   -  person Ehsan Sajjad    schedule 13.06.2015
comment
Использование модели представления всегда лучше, чем ViewBag. Почему вы ожидаете, что Model.Accommodations будет заполнено (и использование ViewBag все равно не заполнит его). Вы не должны (и не должны) генерировать входные данные для каждого свойства каждого SelectListItem в коллекции. Если вам нужно вернуть представление, потому что ModelState недопустимо, вы переназначаете SelectList свойству Accommodations, прежде чем возвращать представление.   -  person    schedule 14.06.2015
comment
@Stephen Ожидалось, что Размещение будет нулевым (т.е. не заполненным), поскольку это только значения поиска. Поскольку это значения поиска, я хочу сохранить только фактически выбранный идентификатор, а не значения цикла (по очевидным причинам). Проблема в том, что я не знаю, как предоставить значения поиска в представление, используя мою модель вместо ViewBag, но все же не сделать их частью SaveChanges(). Я хочу только сохранить идентификатор выбранного элемента в раскрывающемся списке. Извините, если мой OP был неясен.   -  person ImproWise    schedule 14.06.2015
comment
Не уверен, что понимаю - зачем вам сохранять SelectList (или вы добавили это свойство в свою модель данных? - в этом случае нет - принадлежит модели представления)   -  person    schedule 14.06.2015
comment
@Stephen Ну, это вопрос на миллион долларов :) На самом деле они не являются частью модели, так что вы правы в этом, но я знаю только 2 способа получить возможные значения поиска для представления: с помощью ViewBag или с помощью моя модель. Возможно, ответ на этот вопрос прост: используйте ViewBag для отправки значений Lookup в представление.   -  person ImproWise    schedule 14.06.2015
comment
Представление не должно использовать модель данных. У вас должна быть модель представления, включающая свойство SelectList (модель данных не содержит свойства SelectList). В контроллере инициализируйте новый экземпляр модели представления и отправьте его в представление. В методе POST инициализируйте новый экземпляр вашей модели данных и сопоставьте с ним свойства модели представления, а затем сохраните модель данных. См. также Что такое ViewModel в MVC?   -  person    schedule 14.06.2015
comment
@Stephen Да, это, вероятно, лучшее решение, которое, скорее всего, будет использоваться, когда вы перейдете на N-уровень. В настоящее время я немного экспериментирую с быстрым и грязным 1-уровневым решением, поэтому модель представления и модель данных одинаковы, но в реальном бизнес-приложении это, надеюсь, не так. Спасибо за ваше предложение.   -  person ImproWise    schedule 14.06.2015
comment
Я думаю, вы можете увидеть пример здесь: codeproject.com/Articles/702890/   -  person Amir Mahmoodi    schedule 15.06.2015


Ответы (1)


В действии отправки вашего контроллера просто перезагрузите список Accommodations из базы данных, как вы это делаете в действии получения.

Обычно вы делаете это, если в modelstate есть ошибки, и вы хотите передать их обратно в представление, иначе нет необходимости перезагружать список выбора. Вы не указали, где именно он дает нулевую ссылку, поэтому я предполагаю, что у вас есть ошибки состояния модели и перезагружаете представление, чтобы показать ошибки на стороне сервера. например:

[HttpPost]
public ActionResult EditAccommodation(AccommodationViewModel model)
{
    if (!ModelState.IsValid) 
    {
        model.Accommodations = new SelectList(db.Accommodations.ToList(), "AccommodationID", "Name");
        return View(model);
    }

    // else modelstate ok and model.AccommodationID set 
    ...
}

Кроме того, я рекомендую вам четко указывать имена переменных, например:

public virtual SelectList AccommodationSelectList { get; set; }

затем, когда вы обращаетесь к Accommodations, становится ясно, является ли это списком выбора (который на самом деле не является списком приспособлений, это список выбранных элементов) или реальным списком приспособлений из базы данных.

person freedomn-m    schedule 13.06.2015
comment
Спасибо за ваш ответ. Возможно, я был неясен в своем ОП, извините за это. Я только хочу сохранить идентификатор выбранного элемента в раскрывающемся списке. Остальные элементы являются просто поисковыми значениями. Но я не знаю, как предоставить значения поиска через модель, но все же убедиться, что SaveChanges() не пытается сохранить их в базе данных как часть LoanApplication. Как упоминалось ранее, решение ViewBag работает нормально, но мне не очень нравится использовать ViewBag. - person ImproWise; 14.06.2015
comment
В приведенном выше коде значения поиска не будут загружаться из БД во время сохранения. Вы можете легко заменить "viewbag", создав класс специально для представления (модель представления). Это будет работать точно так же, как ViewBag, но строго типизировано. Возможно, вы захотите обновить свой вопрос и добавить тег entity-framework, если вопрос больше касается «SaveChanges ()» (или добавить свой код для SaveChanges), поскольку в настоящее время в тексте вопроса нет ничего, касающегося проблемы с сохранением поиска. - person freedomn-m; 15.06.2015