Коли використовувати шаблон сховища


20

Нещодавно я читав, що не дуже корисно використовувати шаблон сховища спільно з ORM. Наскільки я розумію, це тому, що абстракція, яку вони надають над базою даних SQL, є надто герметичною, щоб її містити шаблон.

У мене є кілька запитань з цього приводу:

  1. Що робити, якщо ви хочете вимкнути ORM? У вашій програмі ви матимете специфічний для ORM код, якщо ви не будете містити його у сховищі.

  2. Чи все ще шаблон дій репозиторію дійсний, коли ви не використовуєте ORM, а ви використовуєте ADO.NET для доступу до даних та заповнення даних об'єкта самостійно?

  3. Якщо ви використовуєте ORM, але не шаблон сховища, де ви зберігаєте поширені запити? Чи було б розумно представляти кожен запит класом і мати якусь фабрику запитів для створення екземплярів?


1
1) ви ніколи не зможете поміняти ORM через свою різну поведінку, навіть якщо обидва підтримують linq, вони поводяться досить різними, щоб ваша програма зламалася. наприклад, ледача поведінка завантаження, брудне відстеження, привидні проксі тощо. Однак приємно мати можливість замінити ORM для внутрішньої пам’яті для тестування ..
Roger Johansson

Для чого це варто, я беру участь у дискусії про сховища / ORM тут: stackoverflow.com/questions/13180501/…
Ерік Кінг

Де ви читали, що це погана практика?
Дейв Хіллер

Відповіді:


3

1) Правда, але як часто ви вимикаєте ORM?
2) Я б сказав так, тому що контекст ORM є схожим на сховище і приховує багато роботи, пов’язаної зі створенням запитів, завантаженням даних, картографуванням і т. Д. Якщо ви не використовуєте ORM, то ця логіка все ще повинна десь знаходитися. Я не знаю, чи було б це кваліфіковано як зразок сховища в найсуворішому значенні цього слова, хоча ...
3) Запитання інкапсуляції - це те, що я часто бачу, але це, як правило, більше для тестування / заглушки. Крім цього, я був би обережний, коли повторно використовуєте запит у різних частинах програми, оскільки тоді ви ризикуєте створити залежність від чогось, що може змінитися n-разів (n - кількість місць, де ви використовуєте запит).


1
1) Ви ставите неправильне запитання. Не важливо, як часто, це просто має бути один раз. З огляду на кількість доступних варіантів ORM, можливо, буде кращий той, який ви вже використовуєте. Тепер стає питанням: що відбувається, коли ти робиш? Сховище дає вам гарну абстракцію. Я був там, і хотілося б, щоб я зробив таку абстракцію в першу чергу.
devnull

3
@devnull Я не згоден. Якщо це станеться не пізніше, я вважаю це прийнятним ризиком. Якщо ви боїтеся зробити неправильний вибір: експериментуйте більше, перш ніж приступити до одного. Теоретично така абстракція звучить приємно, але на практиці ви закінчуєте відтворювати досить велику частину api вашого ORM, все тому, що ви можете закінчитись, вибравши колись десь іншу. Для мене це витрачені витрачені зусилля, зайвий код та більше коду, який ви самі повинні підтримувати та гарантувати. Крім того, перемикання ORM не повинно впливати на всю програму; навчитися розміщувати межі домену.
Штефан Білліет

Зміна ORM - не єдина причина для сховища. Якщо вам потрібно ввести [розподілений] кеш у вашій програмі - всі зміни будуть зроблені в сховищі, і ваш BL не зміниться через зміни рівня доступу до даних.
Валерій

невже розподілений кеш не вбудовується в ORM у більшості випадків?
користувач1450877

Я думаю, це залежить від ОРМ. Ви можете вирішити пройти більш легку ORM, ніж NHibernate або EF.
Валерій

2

1) Що робити, якщо ви хочете вимкнути ORM, у вашій програмі буде вказаний специфічний код ORM, якщо ви не будете містити його у сховищі.

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

Тоді я мав би іншу збірку для конкретної реалізації свого рівня доступу до даних. Наприклад, у мене можуть бути:

Company.Product.Dataі Company.Product.Data.EntityFrameworkзбірок. Перша збірка буде використовуватися виключно для інтерфейсів, коли інша буде конкретною реалізацією логіки доступу до даних Entity Framework.

2) Чи все ще діє схема репозиторію, коли ви не використовуєте ORM, і ви використовуєте ADO.net для доступу до даних та заповнення даних об'єкта самостійно?

Я думаю, що вам вирішувати, яка модель справедлива чи ні. Я використовував шаблон репозиторію в шарі презентації. Слід пам’ятати, що люди люблять кидати відповідальність у сховища. Перш ніж ви це дізнаєтесь, ваш клас сховища буде танцювати, співати та робити всілякі речі. Ви хочете цього уникнути.

Я бачив клас сховища, який розпочався завдяки обов'язкам GetAll, GetById, Update та Delete, що добре. На той момент, коли проект був завершений, той самий клас мав десятки методів (обов'язків), яких ніколи не було. Наприклад, GetByForename, GetBySurname, UpdateWithExcluds та всілякі шалені речі.

Тут грають запити та команди.

3) Якщо ви використовуєте ORM, але не шаблон сховища, де ви зберігаєте загальновживані запити. Чи було б розумно представляти кожен запит класом і мати якусь фабрику запитів для створення екземплярів?

Я думаю, що це дуже гарна ідея використовувати запити та команди замість сховищ. Я роблю наступне:

  • Визначте інтерфейс для запиту. У цьому вам допоможе одиничне тестування. Напрpublic interface IGetProductsByCategoryQuery { ... }

  • Визначте конкретну реалізацію для запиту. Ви зможете вводити їх через IoC-рамку на ваш вибір. Напрpublic class GetProductsByCategoryQuery : IGetProductsByCategoryQuery

Тепер замість забруднення сховища з десятками обов'язків я просто групую свої запити в простори імен. Наприклад, інтерфейс для вищезазначеного запиту може містити: Company.SolutionName.Products.Queriesа реалізація може житиCompany.SolutionName.Products.Queries.Implementation

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

Деякі можуть погодитись і сказати, що до завершення проекту у вас буде десятки класів та просторів імен. Так, ти будеш. На мій погляд, це гарна річ, оскільки ви можете переглядати рішення в IDE на ваш вибір і миттєво бачити, які обов'язки є певним компонентом. Якщо ви вирішили скористатися шаблоном сховища, вам доведеться заглянути все до класу сховищ, намагаючись розробити його обов'язки.


Мені подобається ідея мати команди замість загальних функцій. Де я можу прочитати більше про те, як їх реалізувати в контексті доступу до даних?
ankush981

1

ВІДМОВА ВІДПОВІДАЛЬНІСТЬ: Далі базується на моєму розумінні та короткому досвіді зазначеного шаблону (сховища, яке є). Я можу зробити це неправильно ... насправді я досить впевнений, що я роблю це неправильно :). Отже, хоча це спроба відповіді, це також питання в маскуванні.

Я використовую шаблон репозиторію, щоб абстрагувати рівень доступу до даних, який у більшості випадків є ОРМ. Це загальний інтерфейс, на сьогоднішній день з методами створення, читання, оновлення, видалення та впровадження класів LINQ для SQL та EF. Я міг би зробити реалізацію, яка записує файли XML на диск (просто дивний приклад того, що я міг би зробити з цим). Я не виконую одиницю роботи, оскільки вона підтримується ОРМ. Якщо потрібно, я, мабуть, міг би це здійснити. Мені це подобається, тому що, поки що, це добре розлучило мене. Я не кажу, що кращих альтернатив немає.

Щоб відповісти на ваші запитання:

  1. Вам це подобається чи ні, зміни відбудуться. І якщо ви написали купу додатків і прийшов час їх підтримати, але відчуваєте, що болісно працювати з поточною ОРМ та хочете змінити її, ви похвалите себе за те, що зробили таку абстракцію. Просто використовуйте все, що вам подобається, будь то сховище чи інший шаблон / концепція.
  2. Так, поки ви використовуєте його для розділення доступу до даних. Як я вже згадував раніше, ви можете зробити реалізацію, яка записує дані в плоскі файли.
  3. Я використовую Репозиторій, щоб зберігати мої часто використовувані запити та об’єкти запитів, коли у мене є запити, які я хочу налаштувати (яких не так багато).

Щоб навести ще один приклад, хлопці з Umbraco відібрали контейнер DI, про всяк випадок, якщо вони захочуть перейти на щось інше.


0

Якщо ORM пропонує гнучкість LINQ, прагнення до завантаження і т. Д., Я б не ховав її за додатковим шаром.
Якщо він включає необроблений sql (micro ORM), то для досягнення повторного використання все одно слід застосовувати "метод за запитом", завдяки чому модель репозиторію добре підходить.

What do you do if you want to switch out ORMs? 
You would have ORM specific code in your application if you do not contain it in a repository.

Навіщо вам потрібно перемикатися?
Той, який має більшість необхідних функцій, повинен бути використаний. Цілком можливо, що новий випуск ormX приносить нові функції і виявляється кращим за поточний, але ...
Якщо ви вирішите сховати орму, ви можете використовувати лише ті функції, які мають усі кандидати.
Наприклад, ви не можете використовувати Dictionary<string, Entity>властивості у ваших організаціях, оскільки ormY не може впоратись із ними.

Якщо припустити, що LINQ використовується, більшість перемикачів orm - це просто перемикання посилань на бібліотеку та заміна session.Query<Foo>()на context.Foosабо подібні до тих пір, поки вона не компілюється. Завдання нудне, але займає менше часу, ніж кодування шару абстракції.

Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?

Так. Код повинен бути багаторазовим, а це означає розміщення будівлі sql, матеріалізації об'єктів тощо в одному місці (окремий клас). Ви можете також зателефонувати до класу "XRepository" і витягти з нього інтерфейс.

If you use an ORM but not the repository pattern where do you keep commonly used queries? 
Would it be wise to represent each query as a class and have some sort of query factory to create instances?

Якщо припустимо, що LINQ використовується, класова обгортка буде надмірною IMHO. Більш добрим способом були б методи розширення

public static IQueryable<T> Published<T>(this IQueryable<T> source) where T : Page
{
    // at some point someone is going to forget to check that status
    // so it makes sense to extract this thing
    return source.Where(x => x.Status == Status.Published && x.PublishTime <= DateTime.UtcNow);
}

Будь-який код, який використовується в декількох місцях (або має потенціал) і досить складний (схильний до помилок), повинен бути вилучений в централізоване місце.

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