Шаблон репозитория против DAL

93

Это одно и то же? Только что закончил смотреть учебник Роба Коннери «Витрина», и они кажутся похожими на технику. Я имею в виду, что когда я реализую объект DAL, у меня есть методы GetStuff, Add / Delete и т. Д., И я всегда сначала пишу интерфейс, чтобы потом можно было переключить db.

Я что-то путаю?

Майк
источник

Ответы:

88

Вы определенно не тот, кто все путает. :-)

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

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

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

Некоторые люди будут накладывать больше ограничений DDD на репозиторий, в то время как другие будут использовать репозиторий в качестве удобного посредника между базой данных и уровнем сервиса. Репозиторий, такой как DAL, изолирует уровень сервиса от специфики доступа к данным.

Одна проблема реализации, которая, кажется, их отличает, заключается в том, что репозиторий часто создается с помощью методов, которые принимают спецификацию. Репозиторий вернет данные, удовлетворяющие этой спецификации. Большинство традиционных DAL, которые я видел, будут иметь больший набор методов, в которых метод будет принимать любое количество параметров. Хотя это может показаться небольшой разницей, это большая проблема, когда вы входите в области Linq и Expressions. Интерфейс нашего репозитория по умолчанию выглядит так:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

Это DAL или репозиторий? В этом случае, я думаю, и то, и другое.

Ким

Ким Мейджор
источник
5
Поздно на вечеринку, но почему T [], а не List <T> (или аналогичный)?
Майк Кингскотт,
27
Возможно, IEnumerable <T> будет лучшим.
Venemo
9
или IQueryable <T>
kenwarner 02
1
Я думаю, что IQueryable <T> будет лучшим выбором, потому что он позволяет связывать методы и откладывать выполнение, позволяя базе данных делать всю работу.
0lukasz0
4
@kenwarner Я думаю, что возвращение IQueryable <T> приводит к утечке абстракции. Вы должны вернуть объекты домена из своего репозитория.
Мэтью
42

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

Репозиторий может быть DAL, но он также может располагаться перед DAL и действовать как мост между уровнем бизнес-объекта и уровнем данных. Используемая реализация будет варьироваться от проекта к проекту.

Джероми Ирвин
источник
23

Одно большое отличие состоит в том, что DAO - это общий способ работы с постоянством для любого объекта в вашем домене. С другой стороны, репозиторий имеет дело только с совокупными корнями.

громоздкий
источник
26
Первое, что нужно понять, это то, что репозиторий как шаблон является частью более крупной системы, известной как Domain Driven Design. В домене DDD объекты сгруппированы в агрегаты, каждый из которых имеет агрегированный корень. Например, PurchaseOrder - это совокупный корень, а OrderItems - дочерние элементы в совокупном корне. Репозиторий имеет дело только с совокупными корнями. То есть, например, OrderItem никогда не загружается независимо от его совокупного корня. Таким образом, у вас никогда не будет репозитория OrderItem в DDD. Однако в системе без DDD у вас может быть OrderItemDao, поскольку Dao не ограничивается агрегированными корнями.
pondermatic
НГ, спасибо! Я начал видеть это таким образом, но теперь это проясняет. Я должен начать читать всю литературу DDD!
Дэвид
@bingle, отличное описание агрегированных корней и того, как дочерние объекты загружаются в репозиторий. Где мог бы существовать репозиторий в многослойном приложении? Я мог видеть, что он находится в библиотеке уровня доступа к данным, но, поскольку он загружает дочерние объекты, должен ли он существовать в библиотеке уровня логики? Моя интуиция подсказывает мне уровень доступа к данным, но мне нужно ваше мнение по этому поводу.
Джефф ЛаФэй 05
12

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

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

Я могу даже зайти так далеко и заявить, что, если шаблон репозитория не используется вместе с шаблоном спецификации, на самом деле это не «репозиторий», а DAL. Надуманный пример в псевдокоде:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

Подробности см. В Спецификационном эссе Фаулера (на этом я основал сказанное выше).

DAL будет иметь специализированные методы, такие как

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

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

В .NET запросы LINQ могут быть одним из способов реализации спецификаций, но объединение спецификаций (выражений) может быть не таким гладким, как в случае собственного решения. Некоторые идеи для этого описаны в этом вопросе SO .

Томас Юнг
источник
2

Лично я считаю, что все дело в картировании, см. Http://www.martinfowler.com/eaaCatalog/repository.html . Таким образом, вывод / ввод из репозитория - это объекты домена, которые в DAL могут быть любыми. Для меня это важное дополнение / ограничение, так как вы можете добавить реализацию репозитория для базы данных / службы / чего угодно с другим макетом, и у вас есть четкое место, где можно сосредоточиться на выполнении сопоставления. Если вы не должны использовать это ограничение и иметь отображение где-то еще, то наличие разных способов представления данных может повлиять на код там, где он не должен изменяться.

eglasius
источник
1

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

c00ke
источник
1

Во внешнем мире (т.е. клиентского кода) репозиторий такой же, как DAL, за исключением:

(1) его методы вставки / обновления / удаления ограничены использованием объекта контейнера данных в качестве параметра.

(2) для операции чтения может потребоваться простая спецификация, такая как DAL (например, GetByPK), или расширенная спецификация.

Внутри он работает с уровнем сопоставления данных (например, контекстом структуры сущностей и т. Д.) Для выполнения фактической операции CRUD.

Что не означает шаблон репозитория: -

Кроме того, я видел, как люди часто путают наличие отдельного метода Save в качестве примера реализации шаблона репозитория, помимо методов Insert / Update / Delete, которые фиксируют все изменения в памяти, выполняемые методами вставки / обновления / удаления в базу данных. У нас может быть метод Save определенно в репозитории, но репозиторий не обязан изолировать CUD в памяти (создание, обновление, удаление) и методы сохранения (которые выполняют фактическую операцию записи / изменения в базе данных), но Ответственность за шаблон Unit Of Work.

Надеюсь это поможет!

Ашраф Алам
источник
1

Репозиторий - это шаблон, это способ реализовать вещи стандартизованным способом, чтобы повторно использовать код, насколько это возможно.

Xulfee
источник
1

Преимущество использования шаблона репозитория состоит в том, чтобы имитировать уровень доступа к данным, чтобы вы могли протестировать код бизнес-уровня, не вызывая код DAL. Есть и другие большие преимущества, но это кажется мне очень важным.

Шайлеш
источник
1
Вы все равно можете имитировать DAL, это не обязательно должен быть репозиторий как таковой. Важным моментом является то, что какая бы стратегия доступа к данным вы ни использовали, она должна реализовывать интерфейс. Это позволит вам использовать контейнеры IoC, а также аккуратно протестировать свой бизнес-код без необходимости хранения данных.
cdaq
0

Насколько я понимаю, они могут означать в основном одно и то же, но название зависит от контекста.

Например, у вас может быть класс Dal / Dao, реализующий интерфейс IRepository.

Даль / Дао - это термин уровня данных; более высокие уровни вашего приложения думают о репозиториях.

удаленный фасад
источник
0

Итак, в большинстве (простых) случаев DAO - это реализация репозитория?

Насколько я понимаю, кажется, что DAO имеет дело именно с доступом к db (CRUD - хотя и не выбирает ?!), в то время как Repository позволяет абстрагироваться от всего доступа к данным, возможно, являясь фасадом для нескольких DAO (возможно, разных источников данных).

Я на правильном пути?

Майк
источник
На самом деле я бы изменил это и сказал, что с упрощенной точки зрения репозиторий - это особый стиль реализации для DAO, но да, вы на правильном пути. (R от CRUD = Читать, так что это ваш выбор.)
Джероми Ирвин,
0

Можно утверждать, что «репозиторий» - это определенный класс, а «DAL» - это весь уровень, состоящий из репозиториев, DTO, служебных классов и всего остального, что требуется.

Джонатан Аллен
источник