Сглаженные и производные свойства с Automapper - PullRequest
1 голос
/ 04 апреля 2011

Я работаю на сайте ASP.NET MVC, используя EF4 и Automapper.Я делаю хорошие успехи и чувствую себя довольно хорошо для дизайна (учитывая, что это мой первый удар по настоящей архитектуре DDD).Но я начинаю видеть некоторые вещи, с которыми мне не слишком удобно.

Вопросы, которые у меня есть, вероятно, больше связаны с моим отсутствием опыта работы с Automapper и DDD, поэтому они могут быть довольно простыми для некоторых изВы должны ответить и указать мне в правильном направлении.Есть также очень хороший шанс, что я пойду по этому поводу совершенно неправильно, но мое руководство основано на том, что я читаю здесь, некоторые из поиска, а некоторые задают мои собственные вопросы.Но я также начинаю понимать, что некоторые из «советов», которые я вижу, противоречат друг другу.

Краткий обзор, моя модель предметной области - это просто сгенерированные POCO из шаблона POCO EF4 (анемичные).Они используются на моем сервисном уровне, и они также доступны моему приложению через сервисный уровень.У меня нет никакого DTO, только моя анемичная модель предметной области, модели представления и Automapper для сопоставления этих двух, согласно совету , который мне дали .Это все хорошо и прекрасно, если предположить, что они могут быть сопоставлены один к одному.

Мои проблемы возникают, когда мне приходится сводить модели моего домена в одну модель представления или когда мне требуется некоторая бизнес-логика для определения свойства модели представления.

Два примера:

Сглаживание

У меня есть две модели: User и UserProfile.Это сопоставление один-к-одному, поэтому оно уже логически плоское - оно просто в двух отдельных моделях.Моей модели представления нужны свойства как User, так и UserProfile в одном объекте.Из того, что я видел, у Automapper нет простого способа сделать это, поэтому я расширил свой User POCO, добавив в него необходимые свойства UserProfile:

public string UserName
{
    get { return UserProfile.UserName; }
}

Я не большой поклонникэто, как кажется, нарушает СУХОЙ, и может стать чем-то вроде боли, чем больше я должен это делать.

Инкапсуляция бизнес-логики

У меня есть еще один случайгде свойство User не хранится, а выводится и требует некоторой логики перед возвратом значения.Например, URL изображения профиля будет зависеть от того, зарегистрированы ли они в Facebook или Twitter.Итак, у меня есть что-то вроде этого:

public string ProfileImageUrl
{
    get
    {
        if (User.TwitterId != null)
        {
            // return Twitter profile image URL
        }
        if (User.FacebookId != null)
        {
            // return Facebook profile image URL
        }
    }
}

Я почти уверен, что это не то, за что отвечает Automapper, но я не уверен, следует ли это делать с расширением модели домена, если яхочу сохранить анемию.Так что я не уверен, к чему это относится.

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

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

ОБНОВЛЕНИЕ: В ответ на @jfar моя главная проблема с примером выравнивания заключается в том, что это выглядит такдолжно быть что-то, что Automapper должен уметь делать.Если нет, то я могу жить с этим вариантом.Я просто искал кого-то, чтобы дважды проверить мой дизайн, чтобы убедиться, что нет лучшего способа сделать это.

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

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

Ответы [ 4 ]

1 голос
/ 06 апреля 2011
  1. Сглаживание: вы можете связать свои сопоставления вместе, используя способность Automapper сопоставить существующий объект. Пример цепочки
  2. Encapsulatng Business Logic: Я не вижу вашей проблемы.Тем не менее, если вы хотите, чтобы Automapper отвечал за это, взгляните на карты до и после или на собственные средства распознавания. Пример пользовательского резольвера
1 голос
/ 06 апреля 2011

Почему вы так хотите сохранить анемию в своей доменной модели?Мне кажется, что ваши доменные объекты - не что иное, как DTO.

ProfileImageUrl принадлежит вашему классу домена, который имеет необходимую информацию для возврата правильного URL.Я предполагаю, что это UserProfile.Если у одного класса нет необходимой информации, для этого нужен сервис.Вы либо создаете метод в своем сервисе, который возвращает URL, либо составной объект, как предложил Дарин Димитров.

Ответы Firestrand и Дарина Димитрова являются хорошими способами добиться выравнивания.

0 голосов
/ 23 апреля 2011

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

Ключ заключается в присвоении имени свойству целевого объекта полного имени графа исходного объекта.

Исходные объекты:

class User
{
    int Id { get; set; }
    FacebookUser FacebookUser { get; set; }
}

class FacebookUser
{
    string UserName { get; set; }
}

Объекты назначения:

class UserViewModel
{
    int Id { get; set; }
    string FacebookUserUserName { get; set; }
}

Итак:

UserViewModel.Id -> User.Id
UserViewModel.FacebookUserUserName -> User.FacebookUser.UserName

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

0 голосов
/ 04 апреля 2011

Определите модель, которая объединяет эти две модели:

public class UserWithProfile
{
    public User User { get; set; }
    public UserProfile Profile { get; set; }
}

тогда ваш сервисный уровень вернет эту модель. Другая возможность, если между User и UserProfile есть соответствие 1: 1, это определить следующую модель:

public class UserWithProfile: User
{
    public UserProfile Profile { get; set; }
}

Затем определите модель представления, содержащую только то, что необходимо для данного представления:

public class SomeUserViewModel
{
    ... only properties needed by the given view
}

Затем определите отображение между вашей моделью и моделью представления:

Mapper.CreateMap<UserWithProfile, SomeUserViewModel>()
      ...

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

...