MVC 3 — Как это вообще будет работать?

#c# #asp.net-mvc #asp.net-mvc-3 #poco

#c# #asp.net-mvc #asp.net-mvc-3 #poco

Вопрос:

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

Я либо что-то упускаю, либо Microsoft действительно испортила MVC. Я работал над проектами Java MVC, и они были чистыми и простыми. Однако это полный беспорядок, IMO. Примеры в Интернете, такие как NerdDinner и проекты, обсуждаемые на ASP.Net слишком просты, поэтому они «просто» работают. Извините, если это звучит негативно, но это мой опыт на данный момент.

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

Мой уровень данных НЕ зависит от постоянства, так как классы были сгенерированы SQL metal. Из-за этого у меня много ненужной функциональности. В идеале я хотел бы иметь POCO, но я пока не нашел хорошего способа добиться этого.

* Обновление: Конечно, Microsoft ничего не напутала — это сделал я. Я не до конца понимал инструменты, которые были в моем распоряжении. Главный недостаток в том, что я сделал, заключался в том, что я выбрал неправильную технологию для сохранения моих сущностей. LINQ to SQL хорошо работает в приложениях с отслеживанием состояния, поскольку контекст данных можно легко отслеживать. Однако это не относится к контексту без гражданства. Какой был бы правильный выбор? Сначала код Entity Framework или только код работает довольно хорошо, но что более важно, это то, что это не должно иметь значения. MVC или интерфейсные приложения, должно быть, не должны знать о том, как сохраняются данные. *

При создании объектов я могу использовать привязку объекта:

 [HttpPost]
public ActionResult Create(Customer c)
{
    // Persistance logic and return view
}    
  

Это отлично работает, MVC выполняет некоторую привязку за сценой, и все «очень хорошо».

Это было не «Очень хорошо». Заказчиком была модель предметной области, и что еще хуже, она зависела от среды сохранения, потому что была сгенерирована SQL metal. Что бы я сделал сейчас, так это разработал свою модель предметной области, которая была бы независима от уровней хранения данных или представления. Затем я бы создал модель представления из моей модели домена и использовал ее вместо этого.

Как только я захочу выполнить что-то более сложное, например — сохранить заказ, который связан с клиентом, кажется, что все ломается:

     [HttpPost]
    public ActionResult Create(Order o)
    {
        // Persistance logic and return view
    }
  

Для сохранения заказа мне нужен Customer или, по крайней мере, CustomerID. Идентификатор пользователя присутствовал в представлении, но к тому времени, когда он добрался до метода Create, он потерял идентификатор пользователя. Мне не нравится сидеть и отлаживать MVC-код, поскольку я в любом случае не смогу изменить его в среде хостинга.

Ладно, немного постонал здесь, извините. Что бы я сделал сейчас, так это создал модель представления под названием NewOrder, или SaveOrder, или EditOrder в зависимости от того, чего я пытаюсь достичь. Эта модель представления будет содержать все интересующие меня свойства. Готовая автоматическая привязка, как следует из названия, свяжет отправленные значения, и ничего не будет потеряно. Если мне нужно пользовательское поведение, то я могу реализовать свою собственную «привязку», и она выполнит свою работу.

Альтернативой является использование FormCollection:

 [HttpPost]
public ActionResult Create(FormCollection collection)
{
   // Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.               
}
  

Это используется в книгах и руководствах, но я не вижу смысла в методе, у которого есть альтернатива: TryUpdateModel — если этот сбой или модель недействительна, он пытается обновить ее любым способом. Как вы можете быть уверены, что это сработает?

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

Другой подход, который я попробовал, — это использование объектов ViewModel — оболочки с правилами проверки. Это звучит как хорошая идея, за исключением того, что я не хочу добавлять аннотации к классам сущностей. Такой подход отлично подходит для отображения данных, но что вы делаете, когда дело доходит до записи данных?

 [HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
    // Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}    
  

** Модель представления — хороший путь вперед. Должен был бы существовать некоторый код сопоставления модели представления с моделью домена, который затем можно было бы передать соответствующему сервису. Это неправильный способ, но это один из способов сделать это. Инструменты автоматического сопоставления — ваши лучшие друзья, и вы должны найти тот, который соответствует вашим требованиям, иначе вы будете писать тонны шаблонного кода.**

Я что-то упускаю или Microsoft MVC3 должен работать именно так? Я не понимаю, как это упрощает ситуацию, особенно по сравнению с Java MVC.

Извините, если это звучит негативно, но это был мой опыт до сих пор. Я ценю тот факт, что фреймворк постоянно совершенствуется, внедряются такие методы, как UpdateModel, но где документация? Может быть, пришло время остановиться и немного подумать? Я предпочитаю, чтобы мой код был последовательным во всем, но с учетом того, что я видел до сих пор, у меня нет никакой уверенности в том, что это правильный путь вперед.

Мне нравится фреймворк. Нам так многому предстоит научиться, и это не намного увлекательнее, чем когда-либо. Вероятно, стоит сделать еще один пост, касающийся веб-форм. Я надеюсь, что это полезно.

Комментарии:

1. Можете ли вы предоставить больше информации, скажем, фактический HTML в клиенте, чтобы проверить, правильно ли настроены имена входных данных, чтобы вернуть CustomerID и добавить его в модель заказа? Это больше похоже на разглагольствование, чем на реальный вопрос.

2. Существует проект AutoMapper, который помогает с сопоставлением оболочек представлений, или, как иногда называют модели представлений, с моделями. Поскольку у меня нет никакого опыта работы с фреймворками Java MVC, мне было бы интересно, как они это решают.

3. Я бы сказал, что использовать объекты linq таким образом — плохая идея: создайте специальные классы для этой цели — это будет намного, намного лучше. Вы можете назвать эти классы ViewModel.

4. Ну, ваш вопрос звучит как «Я собираюсь использовать dating, но мне не нравится читать руководства ..» почти все, что вы ищете здесь, было опубликовано в блогах scottgu, haacked или hanselman.

5. Какие уровни приложений вы планируете использовать? Вы хотите предоставить свою модель домена? Собираетесь ли вы использовать уровень представления? Я думаю, вам просто нужно проводить больше времени с ASP.Net MVC и наберитесь опыта, я мало что знаю о фреймворках Java MVC, но я думаю, что ваши проблемы связаны с отсутствием опыта с ASP.Net MVC. В Asp.NET MVC, M не имеет прямого набора инструментов, это может быть любой ORM, включая NHibernate, LinqToEntities, или вообще без ORM, это могут быть простые DTO, DataContracts и т.д., Но это все еще работает.

Ответ №1:

1) Для случая сохранения заказа и отсутствия CustomerID. Если Order в нем есть свойство CustomerID, и у вас есть строго типизированное представление, то вы можете сохранить это обратно в действие вашего контроллера, добавив

 @Html.HiddenFor(model => model.CustomerId)
  

При выполнении этого связующее по умолчанию model binder заполнит все за вас.

2) Что касается использования модели представления, я бы рекомендовал такой подход. Если вы используете что-то вроде AutoMapper, вы можете частично избавиться от избыточных сценариев отображения. Если вы используете что-то вроде беглой проверки, то вы можете красиво разделить проблемы проверки.

Вот хорошая ссылка на общую ASP.NET Подход к реализации MVC.

Комментарии:

1. Это не решение, поскольку мне рекомендуется использовать сторонние инструменты. Какой смысл, если фреймворк должен обрабатывать это за меня? В JAVA я могу использовать простые старые объекты Java, которые не зависят от сохранения. Эти объекты представляют мою модель предметной области, и я также могу использовать их в моделях представления. На данный момент у меня есть модели просмотра, которые я должен преобразовать в свою модель домена и наоборот при чтении и записи данных. Я не верю, что использование сторонних инструментов — это путь вперед, иначе зачем вообще беспокоиться?

2. @vikp: Вы можете использовать POCO с ASP.NET MVC тоже, но в вашем вопросе упоминалось, что в вашем случае это было невозможно. В любом случае такой подход довольно быстро выходит из строя, и в итоге получаются представления с незакрепленными контрактами и непроверяемым спагетти-кодом. Кроме того, правильное стороннее дополнение может быть весьма полезным и сэкономить вам много времени и усилий — не стоит так быстро отказываться от них. Если вы используете NuGet , их в принципе так же легко добавлять в ваши проекты, как и любую другую сборку.

Ответ №2:

Я не думаю, что ваша проблема в asp.net MVC, но со всеми частями, которые вы решите использовать вместе.

Вы хотите, чтобы это было сыро и просто?

Используйте POCOs повсюду и внедряйте репозиторий там, где вам это нужно.

Я не использовал Java MVC, но это сделало бы весь вопрос менее похожим на разглагольствование, если бы вы включили в него то, как вы решили конкретную проблему.

Давайте проясним некоторые неправильные представления или, возможно, недопонимание:

  • Вы можете передавать сложные объекты через post в представление. Но вы хотите сделать это только в том случае, если это имеет смысл, смотрите следующий пункт
  • Выбранный вами образец вызывает некоторые тревоги. Принятие данных клиента или CustomerID для заказа и отсутствие проверки авторизации может стать большой дырой в безопасности. То же самое можно сказать и о заказе в зависимости от того, что вы принимаете / разрешаете. Это огромный аргумент в пользу использования ViewModels, независимо от POCOs, LINQ, Asp.net MVC или Java MVC.
  • Вы можете передавать простые значения, которые не отображаются через post, в представление. Это делается с помощью скрытых полей (которые asp.net MVC поддерживает очень простое использование значения модели), и в некоторых сценариях он генерирует скрытые поля для вас.
  • Вас никоим образом не заставляют использовать linq2sql с Asp.net MVC. Если вы обнаружите, что он не подходит для того, как вы собираетесь его использовать, отойдите от него. Обратите внимание, мне нравится linq2sql, но как это связано с вашим представлением о том, что вы можете делать с asp.net mvc странный.
  • «Я работал над проектами Java MVC, и они были чистыми и простыми». Работа над проектом — это не то же самое, что самостоятельное проектирование проекта. Навыки проектирования влияют на то, что вы получаете от чего угодно. Не говорю, что это ваш случай, но просто хотел указать на это, учитывая отсутствие конкретики о том, чего вам не хватает в Java MVC.
  • «Мой уровень данных НЕ зависит от сохранения, поскольку классы были сгенерированы SQL metal. Из-за этого у меня много ненужной функциональности. В идеале я хотел бы иметь POCO, но я пока не нашел хорошего способа добиться этого «. Вы выбрали неправильную технологию, linq2sql не предназначен для соответствия этому требованию. Это не было проблемой в проектах, в которых я его использовал, но все спроектировано таким образом, что менее привязано к его специфике, чем вам кажется. Тем не менее, просто перейдите к чему-нибудь другому. кстати, вам следовало поделиться тем, что вы использовали с Java MVC.
  • «Идентификатор пользователя присутствовал в представлении, но к тому времени, когда он добрался до метода Create, он потерял идентификатор пользователя». Если свойство в порядке, вы можете поспорить, что в вашем коде есть ошибка. Теперь, это был бы совершенно другой реальный вопрос, почему он не использует CustomerID / такой вопрос мог бы возникнуть с: ваш класс Customer, представление, что вы передаете в представление … ответы будут включать, но не ограничиваться: проверьте исходный код HTML в браузере, чтобы увидеть, какое значение вы действительно отправляете в исходном коде (альтернативно используйте fiddler, чтобы увидеть то же самое), убедитесь, что CustomerID действительно имеет значение, когда вы передаете его в представление.
  • Вы сказали: «»волшебный» метод UpdateModel, который иногда работает, а иногда нет». Это не волшебство, вы можете посмотреть, что оно делает, и, конечно же, найти информацию об этом. Что-то не так в информации, которую вы публикуете, моя ставка — необязательные поля или неправильные значения для анализируемой информации… представления поддерживают добавление проверок для этого. Без проверок этого может не хватать.
  • Вы сказали в комментарии: «После вызова UpdateModel я не могу явно задать CustomerID, мне придется извлекать объект customer и затем присваивать его заказу, что кажется накладными расходами, поскольку все, что мне нужно, это CustomerID» … вы принимаете CustomerID, который является пользовательским вводом (даже если это скрытое поле), вы действительно хотите проверить этот ввод. Кроме того, вы противоречите сами себе, вы утверждаете, что вам просто нужен CustomerID , но затем вы говорите, что вам нужен полный объект Customer, связанный с привязкой к заказу. То есть, если вы привязываете только CustomerID, вам все равно нужно получить этого Customer и назначить его свойству. Нет никакой магии, кроме сцен …
  • Также в комментарии: «Модель обновления — это то, чего я сейчас полностью избегаю, поскольку я не знаю, как она будет вести себя с объектами LINQ. В классе view model я создал конструктор, который преобразует объект LINQ в мою view model. Это уменьшило объем кода в контроллере, но все равно кажется неправильным «. Причина использования ViewModel (или EditModel) заключается не в том, что это linq2sql … это потому, что, помимо многих других причин, вы предоставляете модель, которая позволяет манипулировать далеко за пределами того, что вы на самом деле хотите разрешить пользователю изменять. Реальной проблемой является раскрытие необработанной модели, если в ней есть поля, которые пользователю не следует разрешать изменять.

Комментарии:

1. Спасибо за ответ. Все имеет смысл, я опубликую то, что у меня получилось в выходные, поскольку сегодня у меня нет времени. Что касается дыр в безопасности и идентификаторов клиентов — это всего лишь пример, и реальный проект не имеет ничего общего с клиентами и заказами.

2. С .NET MVC3 вы можете использовать POCO с EF4.1, это очень просто, чисто, и вы сохраняете контроль над тем, какую функциональность включать.

Ответ №3:

Если ваше представление определено правильно, вы можете легко это сделать >

     [HttpPost]
    public ActionResult Create(Order o, int CustomerId)
    {
        //you got the id, life back to jolly good (hopefully)
        // Persistance logic and return view
    }
  

Редактировать:

как упоминал аттадиени, под правильным представлением я подразумевал, что у вас есть что-то подобное внутри тега формы >

 @Html.HiddenFor(model => model.CustomerId)
  

ASP.NET MVC автоматически привяжется к соответствующим параметрам.

Комментарии:

1. Привет, спасибо за ответ. Почему я должен передавать CustomerID в качестве отдельного параметра, если customer является частью модели заказа. Привязки к идентификатору недостаточно при работе с сущностями. После вызова UpdateModel я не могу явно задать CustomerID, мне придется извлечь объект customer, а затем назначить его заказу, что кажется накладными расходами, поскольку все, что мне нужно, — это CustomerID.

2. Передача CustomerID работает, но что происходит, когда у меня есть несколько внешних ключей? Сигнатура метода в конечном итоге станет массивной. Вы знаете, почему CustomerID не устанавливается в объекте Order?

3. Клиент является частью заказа? Можете ли вы добавить свою разметку представления? Тогда было бы легче ответить. У меня в голове, если у вас есть @Html.HiddenFor(model => model.Customer.CustomerId) , тогда он будет правильно привязан в ActionResult Create(Order o)

4. это довольно простая концепция. данные, которые получает контроллер, — это только то, что присутствует между <form></form> . Вот как работает HTTP POST. Он не может волшебным образом связать данные из элементов, если они никогда не отправлялись клиенту в первую очередь. Теперь я предполагаю, что в вашем представлении была форма со всеми элементами для Order (включая связанного клиента). Если да, то он может привязываться к Order o . Если нет, то это невозможно. Опять же, как только я увижу вид, мне будет легче указать вам на него.

5. @vikp, прежде чем перейти к представлению для добавления заказа, вы можете: 1) в контроллере создать пустой объект Order, затем присвоить CustomerID, если вы знаете это на тот момент, затем используйте скрытое поле, как многие упоминали здесь. 2) Если пользователь должен выбрать клиента, то покажите в представлении поле со списком, в котором будет сохранен идентификатор клиента, 3) вы всегда можете получить идентификатор клиента в контроллере [post] перед сохранением заказа.

Ответ №4:

Должно быть, я упускаю проблему.

У вас есть заказ контроллера с действием Create, как вы и сказали:

 public class OrderController()
{
    [HttpGet]
    public ViewResult Create()
    {
        var vm = new OrderCreateViewModel { 
            Customers = _customersService.All(),
            //An option, not the only solution; for simplicities sake
            CustomerId = *some value which you might already know*; 
            //If you know it set it, if you don't use another scheme.
        }                             
        return View(vm);    
    }

    [HttpPost]
    public ActionResult Create(OrderCreateViewModel model)
    {
        // Persistance logic and return view
    }  
}
  

Действие Create возвращает модель представления типа OrderCreateViewModel, которая выглядит примерно так.

 public class OrderCreateViewModel 
{
    // a whole bunch of order properties....
    public Cart OrderItems { get; set; }
    public int CustomerId { get; set; }

    // Different options
    public List<Customer> Customers { get; set; } // An option
    public string CustomerName { get; set; } // An option to use as a client side search
}
  

В вашем представлении есть выпадающий список клиентов, который вы могли бы добавить в качестве свойства к viewmodel, или текстовое поле, которое вы подключаете к поиску на стороне сервера через jQuery, где вы могли бы установить скрытое поле CustomerID при поиске соответствия, как бы вы ни решили это сделать. И если вы уже знаете CustomerID заранее (что, по-видимому, подразумевается в некоторых других сообщениях), тогда просто установите его в viewmodel и обойдите все вышеперечисленное.

У вас есть все данные вашего заказа. У вас есть идентификатор клиента, прикрепленный к этому заказу. Все готово.

«Для сохранения заказа мне нужен Customer или, по крайней мере, CustomerID. Идентификатор пользователя присутствовал в представлении, но к тому времени, когда он добрался до метода Create, он потерял идентификатор пользователя.»

Что? Почему? Если CustomerID был в представлении, установлен и отправлен обратно, он находится в модели для метода HttpPost Create, который находится именно там, где вам это нужно. Что вы имеете в виду, это теряется?

ViewModel сопоставляется объекту модели типа order. Как и предлагалось, полезно использовать AutoMapper…

 [HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
    if(!ModelState.IsValid)
    {
      return View(model);
    }   

    // Persistance logic and return view

    var orderToCreate = new Order();

    //Build an AutoMapper map
    Mapper.CreateMap<OrderCreateViewModel, Order>();

    //Map View Model to object(s)
    Mapper.Map(model, orderToCreate);       

    //Other specialized mapping and logic

    _orderService.Create(orderToCreate);

    //Handle outcome. return view, spit out error, etc.
}  
  

Это не обязательно, вы можете сопоставить это вручную, но это просто упрощает задачу.

И все готово. Если вы не хотите использовать аннотации данных для проверки, прекрасно, сделайте это на уровне сервиса, используйте упомянутую библиотеку fluent validation, что бы вы ни выбрали. Как только вы вызовете метод Create () вашего уровня обслуживания со всеми данными, все готово. Где разрыв? Чего нам не хватает?

ответ атаддейни правильный, я просто пытаюсь показать немного больше кода. Голосовать за addeini

Комментарии:

1. Спасибо за ответ. Это работает, и в нем намного больше кода, чем в типичных примерах, которые теоретически должны работать в большинстве сценариев. Я хотел бы иметь возможность легко переходить от моделей представлений к моей модели предметной области, но это оказалось сложным, поскольку сгенерированные LINQ классы не зависят от постоянства. UpdateModel и TryUpdateModel должны выполнять эту работу, но они генерируют исключения в зависимости от объекта, с которым я работаю. Например, если я загружаю объект и его дочерние элементы, UpdateModel завершается с ошибкой, когда TryUpdateModel может завершиться с ошибкой, что, на мой взгляд, неприемлемо.

2. @CodeRush: ViewModels — это решение этой проблемы. AutoMapper разработан, чтобы упростить переход от моделей представлений к моделям предметной области. Хотя на работе мы обернули AutoMapper в общий ITranslator<Tin, TOut> интерфейс, чтобы позже мы могли изменять реализации (AutoMapper работает относительно медленно).

Ответ №5:

Если идентификатор клиента уже есть в модели заказа (в этом примере), он должен быть доступен без расширения сигнатуры метода. Если вы просматриваете исходный код в отображаемом представлении, правильно ли отображается идентификатор клиента в скрытом поле внутри формы? Используете ли вы атрибут [Bind] в классе модели заказа и непреднамеренно препятствуете заполнению идентификатора клиента?

Комментарии:

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

Ответ №6:

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

Попробуйте последовать этому примеру.

1) ВЫПОЛНИТЕ действие перед отправкой в представление, допустим, на этом этапе вы назначаете CustomerID.

 public ActionResult Create()
        {
            var o = new Order();
            o.CustomerID = User.Identity.Name; // or any other wher you store the customerID
            return View(o);
        }
  

2) Представление, если вы не используете какой-либо элемент управления для CustomerID, такой как textbox, combobox и т.д., Вы должны использовать скрытое поле для сохранения значения.

 @using (Html.BeginForm())
    {
        @Html.HiddenFor(m => m.CustomerID)

        <label>Requested Date:</label>
        @Html.TextBoxFor(m => m.DateRequested)

        ...
    }
  

3) Наконец, действие POST для получения и сохранения заказа. Здесь, поскольку CustomerID был сохранен в скрытом значении, Model Binder автоматически поместит все значения формы в объект Order o, тогда вам просто нужно использовать методы CRUD и сохранить его.

 [HttpPost]
public ActionResult Create(Order o)
        {
            return View();
        }
  

Для этого может быть два подхода: один заключается в неявном сохранении всех значений модели, даже если они не используются в представлении, а другой заключается в сохранении только этих используемых значений. Я думаю, что MVC поступает правильно, следуя последнему варианту, избегая ненужного хранения большого количества мусора для больших моделей, когда единственная мысль — назвать один, CustomerName, каким-то образом это может дать вам контроль над тем, какие данные хранить на протяжении всего цикла action-view-action и сэкономить память.

Для более сложных сценариев, где не все поля находятся в одной модели, вам нужно использовать ViewModels . Например, для сценариев mater-detail вы должны создать OrderViewModel, который имеет два свойства: Order o и IEnumerable< OrderDetail > od, но опять же, вам нужно будет явно использовать значения в представлении или использовать скрытые поля.

В последних версиях теперь вы можете использовать классы POCO и Code-Во-первых, это делает все чище и проще, вы можете попробовать EF4 CTP5.

Ответ №7:

если вы используете сервисы (он же; уровень сервиса, бизнес-фасад), для обработки, скажем, OrderModel, вы можете извлечь интерфейс и заставить свой ViewModel / DTO реализовать его, чтобы вы могли передать ViewModel / DTO обратно в службу.

Если вы используете репозитории для прямого управления данными (без уровня servie) в контроллере, то вы можете сделать это старым добрым способом загрузки объекта из репозитория, а затем выполнить для него UpdateModel.

 [HttpPost]
public ActionResult Create(string customerCode, int customerId, Order order)
{
    var cust = _customerRepository.Get(customerId);
    cust.AddOrder(order);//this should carry the customerId to the order.CustomerId
}
  

Кроме того, URL-адреса могут немного помочь там, где это имеет смысл, я имею в виду, что вы можете добавить идентификатор клиента в URL-адрес для создания заказа.

UpdateModel должна работать, если ваша FormCollection имеет значения для ненулевых свойств, и они пусты / null в FormCollection, то UpdateModel должен завершиться с ошибкой.

Комментарии:

1. Модель обновления — это то, чего я сейчас полностью избегаю, поскольку я не знаю, как она будет вести себя с объектами LINQ. В классе view model я создал конструктор, который преобразует объект LINQ в мою view model. Это уменьшило объем кода в контроллере, но все равно кажется неправильным.

2. UpdateModel , обновляет модель (сущность, DTO или ViewModel) из коллекции (запроса. значения формы), я не вижу проблемы с его использованием. И большой вопрос здесь в том, каковы ваши прикладные уровни, хотите ли вы, чтобы ваша модель предметной области была представлена на уровне пользовательского интерфейса? Вы стремитесь к простоте или удобству сопровождения?