Модель ASP.NET MVC для отображения модели с дополнительными вторичными объектами

StackOverflow https://stackoverflow.com/questions/8321277

Вопрос

Я использую 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 свойства, которые являются ключами других объектов, типов альфа и бета. Я заинтересован в увлажнении альфа и бета -версии на основе Alphaid и Betaid Keys.

Сначала я подумал, что использую пользовательские возможности 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 так много, но, возможно, вы можете пройти в детских объектах через функцию карты (чтобы питать цепочки формирования в CreateMap)? Возможно, предложение после карты Александра может сработать, но я не вижу, как вы увлажните «ссылочных» детей, не создавая карту внутри действия контроллера (но тогда вы можете просто использовать кадр и сеанс ворона напрямую и иметь только один Mapper.map).

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

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

Другие советы

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

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


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

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

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

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

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

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

  1. Уровень доступа к данным имеет модель на основе POCO, в которой объекты имеют ссылки друг на друга вместо идентификаторов. Эта модель подвергается воздействию более высоких слоев (например, ViewModel).
  2. DAL имеет единый метод, который загружает все данные, которые необходимы для предполагаемого действия. В вашем случае он должен загружать как Foo, Alpha, бета -сущности. Поскольку это происходит в одном методе DAL, он, вероятно, может сделать это в одном запросе DB. Хотя главный трюк заключается в том, что другим слоям все равно, как это работает.
  3. В вашем контроллере вы используете Automapper, чтобы выравнивать объект Foomodel в FooviewModel, которая является одной из функций Authopper.

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

  1. Только Дал знает, как загружает данные. При необходимости вы изменяете его по своему усмотрению без необходимости изменения кода, связанного с автоматом.
  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; }
}

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

Тем не менее, вам может потребоваться ваша оригинальная структура, похожая на Foomodel, чтобы, например, определить картирование объекта с этой простой структурой. Но все же это исключительно для дала.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top