Проверка модели JPA и обработка транзакций - PullRequest
2 голосов
/ 15 декабря 2011

В настоящее время я выполняю рефакторинг приложения, которое уже использует 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.Я не уверен, что это тоже очень чистый метод.

Что вы думаете об этом?

1 Ответ

0 голосов
/ 19 декабря 2011

Я думаю, чем меньше вы знаете о вашей стойкости в вашем домене, тем лучше. Поэтому в соответствии с мыслями о том, чтобы рассматривать постоянство как услугу для доменной модели, а не рассматривать ее как часть модели, я бы предложил следующее решение:

  • Домен должен быть в согласованном состоянии, всегда;
  • Итак, изменения, поступающие в модель (происходящие из службы, пользовательский интерфейс того, что у вас есть) не могут изменить модель, не зная, что будущая модель проверена.
  • Значение: текущая модель всегда соответствует.

В формуле: Модель будущего = CurrentModel.PerformChanges (). Validated ();

Как это можно сделать? Вероятно, с использованием единицы работы вида строительства. (http://martinfowler.com/eaaCatalog/unitOfWork.html) Всякий раз, когда предметный объект изменяется и проверяется, он вызывает событие, которое он изменяет. Менеджер отдела работы отвечает за выборку этих событий, а затем следит за тем, чтобы материал был помещен в базу данных. Когда изменения не будут подтверждены, событие не возникает, и модель помечается как «недействительная». Поскольку вы работаете в изолированном режиме запроса, это не проблема. Когда вы работаете в модели общего домена, изменения должны быть отменены в вашем домене!

Вероятно, это наиболее академический подход к решению, но, возможно, он помогает начать обсуждение, что делать в этих ситуациях ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...