Связывание модели с родителями / детьми - PullRequest
0 голосов
/ 27 марта 2010

Я уверен, что на этот вопрос уже был дан ответ, но последние три часа я потратил на поиск приемлемого решения и не смог ничего найти, поэтому прошу прощения за то, что, я уверен, повторю.

У меня есть два объекта домена, Player и Position. У игрока есть позиция. Мои доменные объекты - это POCO, связанные с моей базой данных с помощью NHibernate. У меня есть действие Add, которое принимает Player, поэтому я использую встроенную привязку модели. На мой взгляд, у меня есть выпадающий список, который позволяет пользователю выбрать позицию для игрока. Значение раскрывающегося списка - это идентификатор позиции. Все заполняется правильно, за исключением того, что мой объект Position не проходит проверку (ModelState.IsValid), поскольку в точке привязки модели он имеет только Id и ни один из других обязательных атрибутов.

Какое решение для решения этой проблемы с ASP.NET MVC 2 является предпочтительным?

Решения, которые я пробовал ...

  1. Извлечение позиции из базы данных на основе идентификатора перед вызовом ModelState.IsValid в действии Add моего контроллера. Я не могу заставить модель снова выполнить проверку, поэтому ModelState.IsValid всегда возвращает false.
  2. Создайте пользовательский ModelBinder, который наследует от связывателя по умолчанию, и извлеките Position из базы данных после вызова базового связывателя. Кажется, что ModelBinder выполняет валидацию, поэтому, если я использую что-либо из связующего по умолчанию, я попадаю. Это означает, что я должен полностью свернуть свое собственное связующее и извлечь каждое значение из формы ... это кажется действительно неправильным и неэффективным для такого распространенного варианта использования.

Решения, которые, как мне кажется, могут работать, я просто не могу понять, как это сделать ...

  1. Отключить проверку для класса Position при использовании в Player.
  2. Запись пользовательского ModelBinder использует связыватель по умолчанию для большей части привязки свойств, но позволяет мне получить Положение из базы данных ДО того, как связыватель по умолчанию запустит проверку.

Итак, как остальные решают эту проблему?

Спасибо

Dan

P.S. По моему мнению, наличие PositionId на Player только для этого случая не является хорошим решением. Это должно быть решаемо более элегантно.

Ответы [ 3 ]

3 голосов
/ 27 марта 2010

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

0 голосов
/ 05 августа 2011

У меня была такая же проблема в одном из моих приложений. Я решил эту проблему, создав собственный IModelBinder, унаследованный от DefaultModelBinder, и зарегистрировал его с конкретным типом, который я связываю.

Хитрость заключается в том, чтобы использовать session.Load<>, который создает только типизированную ссылку на объект, не запрашивая базу данных. ( Узнайте больше о сессии. Загрузите здесь в блоге Айенде )

/// <summary>
    /// Base for binding references. Usually displayed in dropdowns
    /// </summary>
    public class ReferenceBinder<T> : DefaultModelBinder
        where T : class
    {

        private readonly ISession session;

        public ReferenceBinder(ISession session)
        {
            this.session = session;
        }


        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {

            var idName = CreateSubPropertyName(bindingContext.ModelName, "ID");

            ValueProviderResult result = bindingContext.ValueProvider.GetValue(idName);

            int value;
            return (int.TryParse(result.AttemptedValue, out value)) ?  this.session.Load<T>(value) : null;

        }


    }

В вашем примере вы бы сделали что-то подобное в Global.asax:

ModelBinders.Binders.Add(typeof(Position), new ReferenceBinder<Position>(<pass your current session implementation or use DI/IoC>));

(я использую Castle Windsor для создания фактического связующего и заполнения сеанса в моей реализации)

Предполагается, что ваша модель домена:

        public class Player {
            public virtual Position Position {get;set;}
        }

        public class Position {
            public virtual int ID {get;private set;}
        }

А ваш постбэк выглядит так:

"Position.ID" = <id from dropdown>

РЕДАКТИРОВАТЬ: вам, вероятно, следует использовать подход DTO с выделенными моделями представления. Я узнал это позже. Посмотрите здесь для быстрого старта .

0 голосов
/ 30 марта 2010

Создайте собственный ModelBinder, который может проверить этот конкретный случай для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...