Подтвердить что ты не робот

Нужно ли использовать шаблон репозитория при работе в ASP.NET MVC с решениями ORM?

Мне немного любопытно, какой опыт других разработчиков имеет применение шаблона 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, они действуют как шум, чем полезные абстракции OO. Кажется, что использование шаблона репозитория в упомянутой выше ситуации является не чем иным, как саморазвитием самого разработчика, а также большей помпой и церемонией без каких-либо реальных технических преимуществ. Каковы ваши мысли?

4b9b3361

Ответ 1

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

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

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

Обновление

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

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

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

Обновление 2

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

Вы упомянули только основные действия 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 не предусмотрены, используя непосредственно классы инфраструктуры persistence, особенно в сценариях поиска в реальном мире.