Подтвердить что ты не робот

Практическое использование шаблонов Unit of Work & Repository

Я строю ORM и пытаюсь выяснить, каковы точные обязанности каждого шаблона. Скажем, я хочу перевести деньги между двумя учетными записями, используя Unit of Work для управления обновлениями в одной транзакции с базой данных. Правилен ли следующий подход?

  • Получить их из репозитория
  • Прикрепите их к моему модулю работы
  • Выполнять ли транзакцию и совершать транзакции?

Пример:

from = acccountRepository.find(fromAccountId);
to = accountRepository.find(toAccountId);

unitOfWork.attach(from);
unitOfWork.attach(to);    

unitOfWork.begin();
from.withdraw(amount);
to.deposit(amount);
unitOfWork.commit();

Должно, как и в этом примере, Единица работы и Репозиторий использоваться независимо или:

  • Должна ли Единица работы внутренне использовать репозиторий и иметь возможность загружать объекты?
  • ... или если репозиторий использует внутреннюю единицу работы и автоматически присоединяет любой загруженный объект?

Все комментарии приветствуются!

4b9b3361

Ответ 1

Короткий ответ будет заключаться в том, что репозиторий будет каким-то образом использовать UoW, но я думаю, что взаимосвязь между этими шаблонами менее конкретна, чем первоначально казалось бы. Целью Unit of Work является создание способа по существу объединить группу связанных с базой данных функций, чтобы они могли выполняться как атомная единица. Часто существует связь между границами, создаваемыми при использовании UoW и границами, созданными транзакциями, но эта взаимосвязь больше совпадена.

Образцом хранилища, с другой стороны, является способ создания абстракции, напоминающей коллекцию по сводному корню. Чаще всего такие вещи, которые вы видите в репозитории, связаны с запросом или поиском экземпляров Aggregate Root. Более интересный вопрос (и тот, который не имеет единого ответа) заключается в том, имеет ли смысл добавлять методы, которые касаются чего-то другого, кроме запроса для агрегатов. С одной стороны, могут быть некоторые действительные случаи, когда у вас есть операции, которые применяются к нескольким агрегатам. С другой стороны, можно утверждать, что если вы выполняете операции над несколькими Агрегатами, вы на самом деле выполняете одно действие в другом агрегате. Если вы только запрашиваете данные, я не знаю, действительно ли вам нужно создавать границы, подразумеваемые UoW. Все сводится к домену и как он моделируется.

Эти два шаблона имеют дело с совершенно разными уровнями абстракции, и участие Unit of Work будет зависеть от того, как моделируются также Aggregates. Агрегаты могут захотеть делегировать работу, связанную с сохранением сущностей, которыми она управляет, или может быть другой уровень абстракции между Агрегатами и фактическим ORM. Если ваши агрегаты/сущности имеют дело с персистентностью, тогда может быть целесообразным, чтобы Хранилища также могли управлять этим постоянством. Если нет, тогда нет смысла включать UoW в ваш репозиторий.

Если вы хотите создать что-то для общего публичного потребления вне вашей организации, я бы предложил создать ваши интерфейсы/базовые реализации репозитория таким образом, чтобы они могли напрямую взаимодействовать с вашим ORM или нет в зависимости от потребностей пользователя вашего ORM. Если это внутренне, и вы выполняете работу настойчивости в своих агрегатах .Entities, тогда ваш репозиторий имеет смысл использовать ваш UoW. Для универсального репозитория имеет смысл обеспечить доступ к объекту UoW из реализаций Репозитория, который может быть уверен в том, что он инициализирован и утилизирован соответствующим образом. В этой заметке также будут моменты, когда вы, вероятно, захотите использовать несколько репозиториев в пределах того, что было бы одной границей UoW, поэтому вы хотели бы иметь возможность передать в уже загрунтованный UoW в репозиторий в этом случае.

Ответ 2

Я рекомендую использовать подход, когда репозиторий использует UoW внутренне. Этот подход имеет некоторые преимущества, особенно для веб-приложений.

В рекомендуемом веб-приложении шаблоне использования UoW есть Единица работы (сеанс) для HTTP-запроса. Поэтому, если ваши репозитории будут совместно использовать UoW, вы сможете использовать кеш 1-го уровня (с использованием карты идентификации) для объекта, который был запрошен другими репозиториями (например, словари данных, на которые ссылаются несколько агрегатов). Также вам придется совершать только одну транзакцию вместо нескольких, поэтому она будет работать намного лучше с точки зрения производительности.

Вы можете взглянуть на исходные коды Hibernate/NHibernate, которые являются зрелыми ORM в мире Java/.NET.

Ответ 3

Хороший вопрос!

В зависимости от ваших границ работы. Если они будут охватывать несколько репозиториев, вам может потребоваться создать еще одну абстракцию, чтобы обеспечить покрытие нескольких хранилищ. Он будет похож на небольшой слой "службы", который определен в Domain Driven Design.

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

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