Шаблон сховища та DAL


93

Це одне й те саме? Щойно закінчив переглядати підручник Роберта Коннері з Storefront, і вони, схоже, схожі на техніку. Я маю на увазі, коли я реалізую об'єкт 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 [], а не Список <T> (або подібне)?
Майк Кінгскотт

27
Можливо, IEnumerable <T> буде найкращим.
Венемо,

9
або IQueryable <T>
kenwarner

1
Я думаю, що IQueryable <T> був би найкращим вибором, оскільки він дозволяє ланцюжкові методи та відкладати виконання, дозволяючи базі даних виконати всю роботу.
0lukasz0

4
@kenwarner Я думаю, що повернення IQueryable <T> пропускає абстракцію. Ви повинні повернути об’єкти домену зі свого сховища.
Метью

42

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

Сховищем може бути DAL, але він також може розташовуватися перед DAL і виконувати роль моста між рівнем бізнес-об'єкта та рівнем даних. Яка реалізація використовується, залежить від проекту до проекту.


23

Одна велика різниця полягає в тому, що DAO - це загальний спосіб боротьби з наполегливістю для будь-якої організації у вашому домені. З іншого боку, сховище має справу лише з сукупними коренями.


26
Перше, що слід зрозуміти, це те, що сховище як візерунок є частиною більшої системи, відомої як Design Driven Design. У об'єктах домену DDD об'єднуються в агрегати, кожен з яких має сукупний корінь. Наприклад, PurchaseOrder - це сукупний корінь, а OrderItems є дітьми в корінному корі. Репозиторій має справу лише з сукупними коренями. Тобто, наприклад, OrderItem ніколи не завантажується незалежно від його кореневого кореня. Отже, ви ніколи не матимете сховище OrderItem у DDD. Однак у системі без DDD у вас може бути OrderItemDao, оскільки Дао не обмежується агрегацією коренів.
пондерматичний

НГ, спасибі! Я почав бачити це саме так, але це дає зрозуміти. Мені доведеться почати читати всю літературу DDD!
Девід

@bingle, чудовий опис сукупних коренів та те, як дочірні об’єкти завантажуються сховищем. Де зберігатиметься сховище у багатошаровій програмі? Я міг бачити, що він знаходиться в бібліотеці шарів доступу до даних, але оскільки він завантажує дочірні об’єкти, чи повинен він замість цього існувати в бібліотеці логічного рівня? Моя кишка повідомляє мені про рівень доступу до даних, але я хотів, щоб ви з цього питання висловилися.
Jeff LaFay

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 можуть бути будь-якими. Для мене це важливе доповнення / обмеження, оскільки ви можете додати реалізацію сховища для бази даних / служби / будь-якої іншої верстки, і у вас є чітке місце, щоб зосередитися на виконанні карти. Якщо ви не хочете використовувати це обмеження і мати відображення в іншому місці, тоді наявність різних способів представлення даних може вплинути на код там, де він не повинен змінюватися.


1

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


1

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


1

Перевага використання шаблону сховища полягає у знущанні над рівнем доступу до даних, щоб ви могли протестувати код бізнес-рівня, не викликаючи DAL-код. Є й інші великі переваги, але це, здається, дуже важливо для мене.


1
Ви все ще можете знущатися над DAL, він не повинен бути сховищем як такою. Важливим моментом є те, що будь-яка стратегія доступу до даних, яку ви використовуєте, повинна реалізовувати інтерфейс. Це дозволить вам використовувати IoC-контейнери, а також акуратно перевірити свій бізнес-код, не потребуючи сховища даних.
cdaq

0

Як я розумію, вони можуть означати в основному те саме, але найменування змінюється залежно від контексту.

Наприклад, у вас може бути клас Dal / Dao, який реалізує інтерфейс IRepository.

Dal / Dao - термін рівня даних; вищі рівні вашої програми думають з точки зору сховищ.


0

Тож у більшості (простих) випадків DAO є реалізацією сховища?

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

Я на вірному шляху?


Насправді, я б перевернув це і сказав, що з спрощеної точки зору, Репозиторій є особливим стилем реалізації для DAO, але так, ви на правильному шляху. (R від CRUD = Прочитайте, так що це ваш вибір.)
Джеромі Ірвін

0

У зовнішньому світі (тобто клієнтському коді) сховище те саме, що і DAL, за винятком:

(1) для методів вставки / оновлення / видалення обмежено наявність об’єкта контейнера даних як параметр.

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

Внутрішньо він працює з шаром Mapper Data (наприклад, контекст структури сутності тощо) для виконання фактичної операції CRUD.

Що шаблон сховища не означає: -

Крім того, я бачив, що люди часто плутаються у тому, що вони мають окремий метод збереження як реалізацію зразка шаблону сховища, окрім методів Вставити / Оновити / Видалити, який фіксує всі зміни в пам'яті, виконані методами вставлення / оновлення / видалення до бази даних. Ми можемо мати метод збереження, безумовно, у сховищі, але це не є обов'язком репозиторію за виділення CUD-пам'яті в пам'яті (створення, оновлення, видалення) та методів збереження (що виконує фактичну операцію запису / зміни в базі даних), але відповідальність за підрозділ роботи.

Сподіваюся, це допомагає!


0

Можна стверджувати, що "сховище" - це специфічний клас, а "DAL" - це весь шар, що складається з сховищ, DTO, класів корисності та всього іншого, що потрібно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.