2015-05-06 3 views
3

Позвольте мне начать говорить о проблеме: когда я отправляю свой вид, мое действие получает объект из класса Customer, у которого есть внешние ключи, которые являются целыми, но должны иметь значение NULL.MVC + EntityFramework + проверка поля

Класс был сгенерирован EF Designer, а структура моей базы данных состоит в следующем (я желаю поместить изображение, но он говорит мне, что мне нужно 10 репутации):

Customer (Table) 
    CityId -> City (Table) 
      CityId 
      StateId -> State (Table) 
         StateId 
         CountryId -> Country (Table) 
            CountryId 

RESUMING, я иметь Клиента, который должен находиться в городе, который должен быть связан с государством, которое должно быть связано со страной.

В другой руке у меня есть вид, который имеет 3 выпадающих списка: 1, чтобы выбрать страну, другую - выбрать одно государство из выбранной страны, а третье - выбрать город из выбранного состояния. Когда я выбираю страну, вид (через JSON), заполняю другое выпадающее меню с состояниями и т. Д., Поэтому очевидно, что я сохраняю только CityId.

Проблема заключается в том, когда я пытаюсь представить, то MVC показывает мне следующую проверку:

The CountryId field is required. 
The StateId field is required. 
The CityId field is required. 

Это происходит потому, что эти поля являются Int32. Итак, первое, что я сделал, это изменить, в EF Designer эти поля на nullable (потому что я хочу поставить персональную проверку через ModelState.AddModelError).

Я также изменил Кратность на 0..1.

В базе данных эти поля должны быть недействительными.

Но теперь я получаю следующее сообщение об ошибке: Ошибка 3 Ошибка 3031: Проблема с отображением фрагментов, начинающихся с строки 1074: Столбец с нулевым значением Cidades.EstId в таблице Cidades сопоставляется с свойством nullable entity.

Каков наилучший способ исправить это?

Заранее спасибо

+0

Вы используете модели сущности в своем представлении? Возможно, вы захотите рассмотреть возможность компоновки моделей представления и затем сопоставить их с моделями сущностей перед обновлением. Звучит как хлопот, но AutoMapper действительно помогает там. https://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ –

+0

Привет @SteveGreene! Я использую модели сущностей в моем представлении. В другом крупном проекте я использовал компоновку моделей просмотра, но это тяжелая работа, избыточность и сложность в управлении (когда проект действительно большой). Этот проект будет большим, и я не хочу иметь ту же проблему обслуживания «временных» классов. Я полагаю, что установка поля в ** int? ** (вместо этого только ** int **) является наилучшим способом, но я никогда не делал этого, прежде чем использовать EntityFramework. – Dan

+0

Я бы сказал, что когда проект действительно большой, вам особенно нужно следовать шаблону ViewModel. Это отделяет ваши проблемы и облегчает обслуживание в будущем. Для вашей текущей проблемы вы в конечном итоге сделаете поле с нулевым значением, когда (похоже, это требует бизнес-правило). Automapper - ваш друг здесь. –

ответ

1

Проблемы легко решается: дизайн вида так, что посланная форма содержит только свойство объекта, который вы пытаетесь сохранить в базе данных (Customer).

Что это означает, что:

  • вы должны использовать Html Helpers только для создания элементов управления, связанных с Customer свойств, а не с другими объектами недвижимости. То есть не используйте Html Helpers для создания элементов управления для «Customer.City.CityId», но для «Customer.CityId». Таким образом, вы подтверждаете, что только объекты Customer отправлены в действие вашего контроллера.
  • (Я повторяюсь сам, но) Вы должны избегать создания элементов управления, связанных с любыми другими связанными объектами: городом, государством и страной. Эти элементы управления должны быть обычными объектами HTML. Вы можете получить доступ к ним позже, используя JavaScript (например, для загрузки каскадных списков). Единственный элемент управления, который должен быть связан с любым свойством, - это раскрывающийся список (<select>), который содержит город, который должен иметь имя Customer.CityId, а не Customer.City.CityId.

Если вы сделаете это, когда вы размещаете свою форму, Вы отправляете только Customer объект, таким образом, после действия в контроллере должны получать только параметр Customer. Тогда EF не будет вызывать каких-либо проверок для любых других объектов, просто потому, что они не существуют, и вы избавитесь от проблемы.

О проверке: в зависимости от вашей конфигурации проверка может произойти как на клиенте, так и на сервере. Если вы примете эти меры предосторожности, вы избежите проблем с обеих сторон. Не изменяйте свою модель, чтобы принять нули! Это плохой взлом!

ПРИМЕЧАНИЕ: поскольку вы не показывали свой код, я предполагаю, как он выглядит более или менее. Если мой ответ, что это не достаточно ясно, пожалуйста, обновите ваш вопрос, и дайте мне знать, остроумие комментарий с @JotaBe

+0

Привет @ JotaBe, ваше мнение правильное. Я мог бы это сделать, и, в некотором смысле, вы правы, но это лучший выбор? – Dan

+0

Извините, я по ошибке нарушил оригинальный комментарий. Да, это хорошая практика иметь отдельные классы для создания представления (модель представления) и для получения данных, представленных в действии POST. И это хорошая практика, чтобы отправить на сервер только необходимую информацию, и не более того. Возможно, вы видели простые случаи и учебники, которые используют один и тот же класс для всего. Это делает даже VS scaffolding. Это действительно хорошо для простых случаев (быстро!), Но когда вещь, которую вы используете POST, и то, что вы получаете, так отличается, лучше сделать это так. – JotaBe

+0

Вы хотите управлять отключенным деревом EF, если хотите обновить связанные информация об одной партии (например, корзина для покупок, которая включает в себя детали, является хорошим образцом). Но в этом случае, если вы редактируете Клиента, вам не нужна вся соответствующая информация в «родительских таблицах», которую вы можете получить от своего Клиента. Они уже находятся в базе данных. Их не нужно изменять. Не отправляйте их обратно на сервер, чтобы создать конфутацию – JotaBe

0

Я установил, что удаление первичной проверки введенной MVC:

ModelState.Remove("City.State.CountryId"); 
ModelState.Remove("City.StateId"); 
ModelState.Remove("CityId"); 

Но, то подсказка, которую дала @JotaBe, тоже интересное решение.