Модель ASP.NET MVC для сопоставления модели представления с дополнительными вторичными объектами - PullRequest
3 голосов
/ 30 ноября 2011

Я использую ASP.NET MVC 3 с Raven DB в качестве резервного хранилища данных.У меня есть набор моделей, которые я заинтересован в преобразовании в ViewModels.Для этого я использую AutoMapper, чтобы позаботиться о грязной работе по сопоставлению каждого свойства с соответствующим в ViewModel.Допустим, у меня есть такая модель:

public class FooModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public int BetaId { get; set; }
}

А потом, скажем, я хочу преобразовать ее в ViewModel, например:

public class FooViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public Alpha Alpha { get; set; }
    public int BetaId { get; set; }
    public Beta Beta { get; set; }
}

Моя карта тогда установленапримерно так при запуске приложения:

Mapper.CreateMap<Foo, FooViewModel>();

Затем в контроллере я выполняю карту так:

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var fooInstance = session.Load<Foo>(id);
        var fooViewModel = Mapper.Map<FooViewModel>(fooInstance);
        return this.View(fooViewModel);
    }
}

Проблема в том, что, как вы можете видеть выше,У сущности, выходящей из хранилища, есть 2 свойства, которые являются ключами других объектов, типов Alpha и Beta.Я заинтересован в увлажнении Альфа и Бета на основе ключей Альфа и Бета.

Сначала я подумал, что смогу использовать возможности пользовательского преобразования AutoMapper, но я не думаю, что это сработает, учитывая, что нам потребуется сеанс данных, который будет вставлен в отображение (для вызова хранилища данных для извлеченияАльфа или Бета объект).

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

Где должна происходить гидратация альфа и бета, и каков здесь хороший пример?

Ответы [ 4 ]

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

Я согласен с человеком там, но если вы не можете расширить свою модель, вы всегда можете определить отображение с помощью AfterMap следующим образом:

Mapper.CreateMap<Foo, FooViewModel>()
.AfterMap(MapAlphaBetaFromFooToFooViewModel);


public void MapAlphaBetaFromFooToFooViewModel(Foo foo, FooViewModel fooViewModel)
{
// Here the code for loading and mapping you objects
}

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

1 голос
/ 30 ноября 2011

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

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var foo = session.Load<Foo>(id).Include(....);
        var alpha = session.Load<Alpha>(foo.AlphaId);
        var beta = session.Load<Beta>(foo.BetaId);

        // null checks

        var fooViewModel = Mapper.Map<FooViewModel>(foo);
        fooViewModel.Alpha = Mapper.Map<AlphaViewModel>(alpha);
        fooViewModel.Beta = Mapper.Map<BetaViewModel>(beta);

        return View(fooViewModel);
    }
}  

Я не так часто использовал AutoMapper, но, возможно, вы можете передать дочерние объекты через функцию Map (для подачи цепочек ForMember в CreateMap)? Возможно, предложение Александры AfterMap может сработать, но я не понимаю, как бы вы увлажнили «ссылочных» потомков, не создавая карту внутри действия контроллера (но тогда вы также можете просто использовать ForMember и сеанс Raven напрямую и иметь только один Mapper.Map).

Добавление - Документация AutoMapper предлагает аналогичный метод для вложенных / дочерних карт - https://github.com/AutoMapper/AutoMapper/wiki/Nested-mappings. Хотя это больше похоже на ссылку на объект, чем на ситуацию с идентификатором объекта.

Я не могу пока комментировать другие ответы, но что касается ответа Павла - вы на самом деле не используете Raven таким образом, нет никакого отображения o / r (кроме внутреннего JSON -> объекта) или данных уровень доступа, вы просто используете сеанс Raven напрямую (возможно, через службу, но, конечно, нет необходимости в хранилище или подобном). Что касается ссылок, байт имеет это право, и, как он прокомментировал один из других ответов, лучший подход - сохранить ссылку на идентификатор и использовать включение Raven - это тот же результат и все еще использует только один запрос.

0 голосов
/ 30 ноября 2011

Вы должны заботиться о своей архитектуре в первую очередь.Загрузка данных из БД является обязанностью уровня доступа к данным, и он не должен знать, как организован ваш пользовательский интерфейс.

Я думаю, лучший подход - это следующее распределение обязанностей:

  1. DAL имеет единственный метод, который загружает все данные, необходимые для намеченного действия.В вашем случае он должен загружать обе сущности Foo, Alpha, Beta.Поскольку это происходит в одном методе DAL, он, вероятно, может сделать это в одном запросе БД.Хотя основная хитрость заключается в том, что другим слоям все равно, как он работает.
  2. В вашем контроллере вы затем используете AutoMapper для сглаживания объекта FooModel в FooViewModel, который является одной из функций Automapper.

Ключевые моменты:

  1. Только DAL знает, как он загружает данные.При необходимости вы можете изменить его по своему усмотрению, не изменяя код, связанный с AutoMapper.
  2. AutoMapper отображает данные только из одной структуры в другую и не влияет на стратегию загрузки данных.

Тем не менее, я бы изменил только вашу FooModel:

public class FooModel
{
  public int Id { get; set; }
  public string Name { get; set; }
  public Alpha Alpha { get; set; }
  public Beta Beta { get; set; }
}

и код, который загружает его из БД.

Однако вам может потребоваться ваша исходная структура, похожая на FooModel, для:например, определите объектно-реляционное отображение на эту простую структуру.Но все же это зависит только от DAL.

0 голосов
/ 30 ноября 2011

Одна оптимизация, которую вы могли бы сделать, это загрузить связанный документ за один раз из RavenDB, а не делать отдельный вызов для загрузки каждого связанного документа.См. Документацию RavenDB здесь .

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

...