В настоящее время я выполняю рефакторинг приложения, которое уже использует JPA, но JPA EnitytManager
(и транзакции) в настоящее время ограничены уровнем DAO.Существует также уровень хранилища и уровень обслуживания.Я хочу сделать сервисный уровень транзакционным и иметь один EntityManger
на запрос на сервисном уровне.В идеале я не хочу, чтобы слои службы или репозитория знали что-либо о JPA.
В настоящее время уровни хранилища и службы работают с отсоединенными объектами, полученными из уровня DAO.Изменения вносятся в модель, и объекты объединяются обратно в уровень DAO.В новой структуре объекты остаются управляемыми в течение всего запроса, и 1 запрос содержится в 1 транзакции.Изменения автоматически фиксируются в конце транзакции.Это кажется намного больше в духе JPA и работает довольно хорошо в большинстве распространенных случаев.
Иногда, хотя в модель вносятся изменения, и модель затем проверяется.Если модель больше не действительна, изменения не должны быть сохранены.В старой структуре это было просто:
В этом примере процесс в основном представляет собой граф, и весь граф должен проверяться, никаких собственных ссылок, каждый узел должен быть достижим, у первого узла есть некоторые особые требования, тамдолжен быть конечным узлом и т. д. и т. д. Сначала мы вносим изменения в модель, а затем проверяем модель.
Код слоя репозитория old:
changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
processDao.merge(process);
messages.addInfoMessage("Process was updated succesfully");
}
return messages;
В новой структуре я думаю, что у меня есть три варианта, и я задаюсь вопросом, какой из них считается наилучшим, или есть ли другие альтернативы.
Новая опция кода 1:
changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
messages.addInfoMessage("Process was updated succesfully");
} else {
throw new InvalidProcessException(messages);
}
return messages;
Этот код как бы использует RuntimeException
для проверки некоторых бизнес-правил.Я не думаю, что это считается лучшей практикой, но транзакция откатывается.Это также кажется совместимым, например, с проверкой компонентов, которая также вызывает исключение, если объект не проверяется.
Новый вариант кода 2:
changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
messages.addInfoMessage("Process was updated succesfully");
} else {
em.getTransactionManager.rollback();
}
return messages;
Этот код выполняет откат непосредственно наJPA TransactionManager
и вводит зависимость между моим слоем репозитория и JPA.
Новая опция кода 3:
changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
messages.addInfoMessage("Process was updated succesfully");
} else {
processDao.refresh(process);
}
return messages;
Этот код кажется довольно хорошим, но он зависит от CascadeType.REFRESH
быть правильно установленным в процессе отношений сущностей, которые необходимо обновить.
Я мог бы также, например, processDao.clear();
или processDao.rollback();
Но это увеличивает область действия processDao
до всего entityManger
.Я не уверен, что это тоже очень чистый метод.
Что вы думаете об этом?