Шаблоны для отображения данных между моделями доменов - PullRequest
3 голосов
/ 28 ноября 2011

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

Основная суть всего этого в том, что у меня есть несколько моделей данных, которые смоделированы для удовлетворения ORM и просто выполняют CRUD-операции с объектами. Эти модели в настоящее время выставляются через репозитории / фабрики (зависит от того, является ли их C или RUD).

Затем у меня есть модель представления, которая немного более читабельна и покрыта проблемами пользовательского интерфейса, такими как проверка и отображение данных между представлениями (это сценарий ASP.MVC, но эту ситуацию можно абстрагировать в большинстве ситуаций). ).

Итак, допустим, я захожу в localhost / user / 1, который должен зайти и получить мне пользователя с Id 1 в БД, а затем отобразить его в пользовательском интерфейсе. В конечном итоге для этого необходимо извлечь данные из предметной области, а затем отобразить их в модели пользовательского интерфейса для отображения.

Вот пример сценария:

public class OrmUser
{
    public int Id {get;set;}
    public string Name {get;set;}
    public IList<Permission> Permissions {get;set;}
}

public class UiUser
{
    [Required]
    public int Id {get;set;}
    [Required]
    public string Name {get;set;}
    public bool IsUserAdmin {get;set;}
}

public class UserMapper : IMapper<UiUser>
{
    public UiUser Get(int id)
    {
        var ormUser = UserRepository.Get(id);
        var uiUser = new UiUser
        {
            Id = ormUser.Id,
            Name = ormUser.Name,
            IsUserAdmin = IsUserAdmin(ormUser.Permissions)
        }
    }

    private bool IsUserAdmin(IList<Permission> permissions)
    {
        return permissions.SomeLinq(ToFindIfTheyAreAnAdmin);
    }
}

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

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

Ответы [ 3 ]

5 голосов
/ 28 ноября 2011

В .net вам, вероятно, стоит взглянуть на Automapper

https://github.com/AutoMapper/AutoMapper

Это, по сути, позволяет вам:

CreateMap<Domain.Customer, ViewModel.Customer>()

И вы можете затем отобразитьмежду двумя словами:

var vmCustomer = Mapper.Map<Domain.Customer, ViewModel.Customer>(domainCustomer);

Это, вероятно, сэкономит вам тонну кода котельной плиты.

2 голосов
/ 29 ноября 2011

Да. AutoMapper это инструмент для вас. Есть множество статей по этому поводу, но перейдите к источнику - Джимми Богард. Он главный мастер AutoMapper.

Посмотрите на эту статью блога http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

В наши дни AutoMapper очень эффективно поддерживает MVC, где вы можете украсить свои классы атрибутами, указав, что следует делать.

/ С наилучшими пожеланиями Магнус

1 голос
/ 01 декабря 2011

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

public static class UserPresentationExtensions{
 public bool IsAdmin(this User user){
  return permissions.SomeLinq(ToFindIfTheyAreAnAdmin);
 }
}

Вид будет выглядеть примерно так:

@model User
<fieldset>
 <legend>User: @Model.Name</legend>
 @if(user.IsAdmin()){
  User is an admin
 }
</fieldset>

Чтобы избежать повторного импорта пространства имен, используйте для этого web.config:

<configuration>
 <system.web.webPages.razor>
  <pages pageBaseType="System.Web.Mvc.WebViewPage">
   <namespaces>
    <add namespace="MyProject.PresentationExtensions" />
   ...

У вас есть точка зрения, однако, допустим, вы хотите добавить проверку к своим моделям, поэтому вы решили добавить атрибут [Обязательный] к свойству Name. Хотя тогда, если вы используете совместно используемую модель, ваш уровень данных должен знать об аннотациях, и если ваш уровень данных должен иметь некоторые атрибуты, ваш уровень пользовательского интерфейса должен был бы знать о них. В простейших ситуациях вы правы, иногда проще просто иметь одну модель, являющуюся правдой, и просто обращаться к ней по-другому, но для большинства сложных проектов вам придется испортить обе стороны, пытаясь спасти несколько строк. кода.

Я сказал - в данном конкретном случае. Этот подход применяется только в том случае, если сопоставление на самом деле не стоит и существует только односторонняя связь (вам просто нужно ее визуализировать).

Когда дело доходит до получения сообщений, это немного отличается. В большинстве случаев подход «один размер подходит всем» - это так называемый принцип Thunderdome . То есть:

Все методы Controller принимают один объект ViewModel (или, в некоторых случаях, нулевые объекты) и возвращают один объект ViewModel (один объект входит, один объект уходит).

Тем не менее, довольно часто я предпочитаю пойти по пути расширения / html-помощника и просто передать соответствующие аргументы действию следующим образом:

public void BatheCat(int id /* cat id */, int bathId, string shampoo){
 ...
}

Если счетчик параметров выходит из-под контроля (я не беспокоюсь, пока он <= 3), я просто инкапсулирую их (<a href="https://gist.github.com/1416345" rel="nofollow"> вот пример из моего проекта).

...