Unit Of Work — патерн об'єктно-реляційної поведінки, мета якого полягає у відстежуванні зміни об'єктів під час транзакції. Часто використовується із патерном Repository.
Під час роботи із базою даних важливо відстежувати зміни в об'єктах, в іншому випадку дані не будуть оновлені. Це також вірно для операцій додавання та видалення.
Можна змінювати дані в сховищі при кожній взаємодії з об'єктом, але це призведе до багатьох викликів у базу даних. Очевидно це потребує підтримування транзакції відкритою, що впливає на продуктивність роботи.
Даний шаблон пропонує відстежувати всі зміни над об'єктами та вносити їх у вигляді єдиної транзакції.
Переваги та недоліки
Переваги UnitOfWork покликаний відстежувати всі зміни даних, які ми здійснюємо з доменною моделлю в рамках бізнес-транзакції. Після того, як бізнес-транзакція закривається, всі зміни потрапляють в БД у вигляді єдиної транзакції. Фабрика для репозиторіїв Лінива ініціалізація репозиторіїв (залежно від реалізації) Забезпечує використання одного з'єднання до БД усіма репозиторіями
Недоліки Зростає кількість класів
Опис мовою C# Розглянемо спочатку реалізацію шаблону запропоновану Мартіном Фаулером. Вона передбачає методи для відстеження змін в об'єктах та здійснення транзакції.
Даний шаблон можна адаптувати, до мови програмування. Таким чином використаємо Entity Framework. Нехай дано деякі класи сутностей.
А також припустимо, що патерн Repository для цих сутностей вже реалізований.
Запишемо інтерфейс до Unit Of Work та його реалізацію. Нам більше не потрібно відстежувати зміни у сутностях через те, що ця поведінка реалізована у Entity Framework. Але також це означає, що у нас виникнуть складнощі при зміні фреймворку.
Найпростіша реалізація матиме наступний вигляд:
Недолік полягає у створенні всіх репозиторіїв при ініціалізації Unit Of Work. Забезпечимо їх ліниву ініціалізацію. Перепишемо властивості наступним чином:
Якщо з'являється необхідність додати нову сутність — доведеться кожний раз редагувати клас та інтерфейс, що вміщюють логіку Unit Of Work.
Також актуалізується проблема неможливості вибору специфічної реалізації репозиторію (наприклад, покращеної версії). Вирішити такі проблеми можна, наприклад, наступним чином:
У нинішніх реаліях важливо контролювати доступ багатьох потоків до репозиторію. Поряд із стандартними блокуваннями можна використати вбудовані можливості С#, зокрема клас ConcurrentDictionary: Реалізація може виглядати так:
Залишилось вирішити, те що метод працює із реалізацією, а не абстракцією. Скористаємось фабрикою
Зв'язок з іншими патернами Unit Of Work та Repository часто використовують в парі.
Див. також Шаблони проєктування програмного забезпечення Об'єктно-орієнтоване програмування
Джерела Implementing the repository and unit of work patterns Repository and unit of work pattern Common mistakes with the repository pattern