Что такое паттерн Unit of Work?

«Что такое паттерн Unit of Work?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Unit of Work (Единица работы) — это поведенческий паттерн проектирования, который отслеживает все изменения, сделанные с бизнес-объектами в ходе транзакции, и координирует запись этих изменений в источник данных (например, базу данных). Его основная цель — обеспечить целостность данных и минимизировать количество обращений к БД, группируя несколько операций в одну команду.

Аналогия: Представьте, что вы делаете покупки в супермаркете. Unit of Work — это ваша корзина. Вы кладете в нее товары (новые объекты), меняете их (изменяете объекты), убираете обратно на полку (удаляете объекты). Оплата на кассе (Commit) — это момент, когда все изменения применяются разом.

Ключевые обязанности Unit of Work:

  1. Отслеживание новых объектов, которые должны быть вставлены.
  2. Отслеживание измененных ("грязных") объектов, которые должны быть обновлены.
  3. Отслеживание удаленных объектов.
  4. Управление Identity Map — кэшем, гарантирующим, что один бизнес-объект будет представлен в памяти только одним экземпляром.
  5. Выполнение всех накопленных операций в правильном порядке (вставки, обновления, удаления) при вызове commit().

Практическая реализация в .NET с Entity Framework Core:

// DbContext в EF Core является реализацией Unit of Work.
using (var context = new AppDbContext()) // Начало Unit of Work
{
    // 1. Отслеживание новой сущности (будет INSERT)
    var newAuthor = new Author { Name = "Джон Смит" };
    context.Authors.Add(newAuthor);

    // 2. Отслеживание изменений сущности (будет UPDATE)
    var existingBook = context.Books.First(b => b.Id == 1);
    existingBook.Price = 29.99m; // EF Core отслеживает это изменение

    // 3. Отслеживание удаления сущности (будет DELETE)
    var bookToDelete = context.Books.Find(5);
    context.Books.Remove(bookToDelete);

    // 4. Все изменения (INSERT, UPDATE, DELETE) выполняются одной транзакцией
    // при вызове SaveChanges().
    context.SaveChanges(); // Commit Unit of Work
}

Преимущества использования:

  • Производительность: Группировка запросов (batch operations) снижает нагрузку на БД.
  • Целостность: Все изменения либо применяются вместе (Commit), либо откатываются (Rollback), что поддерживает согласованность данных.
  • Упрощение кода: Разработчику не нужно вручную отслеживать, какие объекты изменились и когда их сохранять.
  • Снижение риска Deadlock: Правильный порядок операций (например, вставки перед обновлениями) помогает избежать взаимных блокировок.

Паттерн является фундаментальным для большинства ORM, таких как Entity Framework, Hibernate, Doctrine.