Нужно ли использовать шаблон репозитория при работе в ASP.NET MVC с решениями ORM? - PullRequest
28 голосов
/ 18 января 2011

Мне немного любопытно, какой опыт имеют другие разработчики в применении шаблона Repository при программировании в ASP.NET MVC с Entity Framework или NHibernate.Мне кажется, что этот шаблон уже реализован в самих ORM.DbContext и DbSet<T> в Entity Framework и ISession в NHibernate.Большинство проблем, упомянутых в шаблоне Repository - как каталогизировано в POEE и DDD - довольно адекватно реализуются этими ORM.А именно, эти проблемы:

  • Постоянство
  • OO Представление данных
  • Абстракция логики доступа к данным
  • Логика доступа к запросу

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

Реализация NHibernate:

public class PostRepository : IPostRepository
{
    private ISession _session;

    public PostRepository(ISession session)
    {
        _session = session;
    }

    public void Add(Post post)
    {
        _session.Save(post);
    }

    // other crud methods. 
}

Entity Framework:

public class PostRepository : IPostRepository
{
    private DbContext _session;

    public PostRepository(DbContext session)
    {
        _session = session;
    }

    public void Add(Post post)
    {
        _session.Posts.Add(post);
        -session.SaveChanges();
    }

    // other crud methods. 
}

Мне кажется, что когда мы используем ORM - такие как Nhibernate или Entity Framework - создание этих реализаций репозитория является избыточным.Кроме того, поскольку эти реализации шаблонов делают не больше, чем то, что уже есть в ORMS, они действуют скорее как noise , чем полезные абстракции OO.Кажется, использование шаблона репозитория в вышеупомянутой ситуации - не более чем самовосхваление разработчика и еще больше помпезности и церемоний без каких-либо ощутимых технических преимуществ.Что ты думаешь ??

Ответы [ 3 ]

12 голосов
/ 18 января 2011

Ответ будет нет , если вам не нужно иметь возможность переключать ORM или иметь возможность тестировать любой класс, имеющий зависимость от вашей ORM / базы данных.

Если вы хотитечтобы иметь возможность переключать ORM или иметь возможность легко тестировать ваши классы, которые используют уровень базы данных: Да, вам нужен репозиторий (со спецификацией интерфейса).

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

Обновление

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

Шаблон репозитория становится великолепным, когда он комбинируется с реализацией UnitOfWork и имеет поддержку шаблона спецификации.

Если вы обнаружите, что все это есть, дайте мне знать :) (У меня есть своя собственная, за исключением хорошо работающей части спецификации)

Обновление 2

Репозиторий - это гораздо больше, чем просто абстрактный доступ к базе данных, как это может сделать ORM.Обычная реализация репозитория должна обрабатывать все статистические объекты (например, Order и OrderLine).Но обрабатывая их в одном и том же классе репозитория, вы всегда можете быть уверены, что они построены правильно.

Но, эй, вы говорите: это сделано для меня автоматически ORM.Ну да и нет.Если вы создаете сайт, вы, скорее всего, захотите изменить только одну строку заказа.Получаете ли вы полный заказ, перебираете его в цикле, чтобы найти заказ, а затем добавляете его в представление?

Тем самым вы вводите логику в свой контроллер, который там не принадлежит.Как вы делаете это, когда веб-сервис хочет то же самое?Дублировать ваш код?

Используя ORM, довольно просто получить любую сущность из любого места myOrm.Fetch<User>(user => user.Id == 1), изменить ее и затем сохранить.Это может быть очень удобно, но также добавляет запахи кода, поскольку вы дублируете код и не можете контролировать, как создаются объекты, если они получили действительное состояние или правильные ассоциации.что вы можете захотеть иметь возможность подписаться на такие события, как «Создано», «Обновлено» и «Удалено» централизованно.Это легко, если у вас есть репозиторий.

Для меня ORM предоставляет способ сопоставления классов с таблицами и ничего более.Мне все еще нравится оборачивать их в репозитории, чтобы иметь возможность контролировать их и получать единую точку модификации.

2 голосов
/ 18 января 2011

Я думаю, что это имеет смысл, только если вы хотите уменьшить уровень зависимости. В резюме вы можете иметь IPostRepository в своем пакете инфраструктуры и несколько независимых реализаций этого интерфейса, построенных поверх EF, NH или чего-то еще. Это полезно для TDD.

На практике сеанс NH (и контекст EF) реализует нечто вроде шаблона «Единица работы». Кроме того, с NH и шаблоном Repository вы можете получить много ошибок и архитектурных проблем.

Например, сущность NH может быть сохранена в обход вашей реализации репозитория. Вы можете получить его из сеанса (Repository.Load), изменить одно из его свойств и вызвать session.Flush (например, в конце запроса, потому что шаблон репозитория не предполагает сброса) - и ваши изменения будут успешно обработаны в дб.

1 голос
/ 18 января 2011

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

Представьте себе, что вы решили использовать сеанс NHibernate непосредственно на уровне приложений.

Вам нужно будет сделать эквивалент предложений WHERE, ORDER BY и т. Д., Используя критерии HQL или NHibernate. Это означает, что ваш код должен ссылаться на NHibernate и содержит идеи, специфичные для NHibernate. Это делает ваше приложение трудным для тестирования и труднее для других, незнакомых с NH. Вызов repository.GetCompletedOrders гораздо более описательный и многократно используемый, чем вызов, включающий что-то вроде «где IsComplete = true и IsDeleted = false ...» и т. Д.

Вместо этого вы можете использовать Linq для NHibernate, но теперь у вас есть ситуация, когда вы легко можете забыть, что работаете над IQueryable. Вы могли бы в конечном итоге создать цепочки выражений Linq, которые генерируют огромные запросы при выполнении, не осознавая этого (я говорю из опыта)! Майк Хэдлоу спровоцировал разговор по существу на эту тему в своем посте Если мой репозиторий выставит IQueryable .

N.b. Если вам не нравится иметь много методов в пользовательских репозиториях для разных запросов (например, GetCompletedOrders), вы можете использовать параметры спецификации (например, Get (спецификации)), которые позволяют вам задавать фильтры, упорядочения и т. Д. Без использования языка доступа к данным.

Возвращаясь к списку преимуществ репозитория, который вы дали:

  • Настойчивость
  • OO Просмотр данных
  • Абстракция логики доступа к данным
  • Логика запросов доступа

Вы можете видеть, что пункты 3 и 4 не предусмотрены при непосредственном использовании классов инфраструктуры постоянства, особенно в сценариях поиска в реальном мире.

...