2010-03-27 4 views
0

Я уверен, что на это был дан ответ раньше, но я потратил последние три часа на поиск приемлемого решения и не смог ничего найти, поэтому я приношу свои извинения за то, что я Конечно, это повторение.Связь с родителями/детьми

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

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

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

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

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

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

Итак, как вы все это решаете?

Спасибо,

Dan

P.S. По-моему, наличие позиции в Player только для этого случая не является хорошим решением. Должна быть разрешена более элегантно.

ответ

3

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

+0

Итак, в основном я должен сделать DTO для всех своих взглядов. Для меня это выглядит довольно неэффективно. У кого-нибудь еще есть решение? – DFX

+0

У меня была такая же мысль, когда я впервые услышал об этом. Но позитивные аспекты тестирования и разделения проблем всегда, кажется, побеждают. Для меня часто быстрее создавать другую модель, чем отлаживать что-то специфичное для домена или создавать пользовательские подборщики моделей. –

0

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

+0

Xeb, у меня возникли проблемы с поиском хорошей информации о пользовательских ModelBinders, думаю, вы могли бы указать мне прямое право? – DFX

0

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

Хитрость заключается в использовании , который создает только типизированную ссылку на объект без запроса базы данных.(Read more about session.Load here in Ayende's blog)

/// <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>)); 

(я использую замок Виндзор, чтобы создать реальное связующее и заполнить сессию в моей реализации)

Если предположить, что модель предметной области является:

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

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

И ваш postback выглядит так:

"Position.ID" = <id from dropdown> 

EDIT: Вы, вероятно, должны использовать подход DTO с выделенными моделями просмотра. Я узнал об этом позже. Have a look here for a quick start.