Сопоставление схемы аудита с Hibernate и AOP - PullRequest
3 голосов
/ 11 ноября 2008

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

  1. Вставьте сумму перевода в таблицу переводов
  2. Вычтите сумму перевода из баланса в Таблице баланса для Счета 1.
  3. Добавить сумму перевода к балансу в таблице баланса для счета 2.

Сообщение родительского аудита для всех таблиц будет выглядеть так: «Пользовательский перевод для суммы XXX»

Это достигается с помощью следующей схемы: Схема

альтернативный текст http://img48.imageshack.us/img48/7460/auditloggingiv6.png

Вопрос в том, как мне представить это в спящем режиме?

Я создал следующее:

В файлах сопоставления баланса и переноса

<set name="auditRecords" table="TransferAuditRecord" inverse="false" cascade="save-update">
  <key>
    <column name="AuditRecordID" not-null="true" />
  </key>
  <one-to-many class="audit.AuditRecord"/>
</set>

Затем классы Transfer и Balance реализуют IAuditable, который имеет методы

public void setAuditRecords(Set<AuditRecord> auditRecord);
public Set<AuditRecord> getAuditRecords();

В файле отображения AuditRecord у меня есть:

<many-to-one name="parentAuditRecord" lazy="false"
             column="parent_id"
             class="audit.AuditRecord"
             cascade="all" />

Затем в классе Logging с использованием перехватчиков AOP и Hibernate у меня есть:

AuditRecord auditRecord = new AuditRecord();
auditRecord.setUser(userDAO.findById(
    org.springframework.security.context.SecurityContextHolder.getContext()
        .getAuthentication().getName()));

auditRecord.setParentAuditRecord(getCurrentActiveServiceRecord());

auditable.getAuditRecords().add(auditRecord);

Затем в классе обслуживания я вызываю следующий метод, заключенный в транзакцию:

save(balance1);
save(balance2);
transfer.setPassed(true);
update(transfer);

parentAuditRecord создается с использованием AOP с потокобезопасным стеком, а AuditRecordType_id устанавливается с помощью аннотаций метода.

Я опустил столбец «пройдено» в таблице переноса. Ранее я звонил в save (перевод), чтобы вставить сумму перевода в таблицу Transfer с переданным значением false. (Это действие также проверяется).

Мои требования немного сложнее, чем в примере выше: P

Итак, последовательность событий для вышеперечисленного должна быть:

  1. Обновить таблицу переноса
  2. Вставить в AuditRecord (родительский)
  3. Вставить в AuditRecord (Child)
  4. Вставить в TransferAuditRecord
  5. Вставить в таблицу баланса
  6. Вставить в AuditRecord (Child)
  7. Вставить в BalanceAuditRecord
  8. Вставить в таблицу баланса
  9. Вставить в AuditRecord (Child)
  10. Вставить в BalanceAuditRecord

Однако описанные выше параметры каскада не выполняются в операторе обновления. Hibernate отказывается вставлять запись в таблицу «многие ко многим» (даже если unsaved-value = «any» в сопоставлении AuditRecord). Я всегда хочу вставлять строки в таблицы «многие ко многим», поэтому потенциально один перенос имеет много записей аудита, отмечающих предыдущие события. Однако последнее событие определяет сообщение, которое пользователь хочет увидеть. Hibernate либо пытается обновить таблицу «многие ко многим» и предыдущие записи AuditRecord, либо просто отказывается вставлять в AuditRecord и TransferAuditRecord, создавая исключение TransientObjectException.

Аудиторское сообщение получается примерно так:

msg=... + ((AuditRecord) balance.getAuditRecords().toArray()[getAuditRecords().size()-1])
    .getParentAuditRecord().getAuditRecordType().getDescription() + ...;

В сообщении должно быть сказано что-то вроде этого: «Имя пользователя установлено как переданное в 12:00 11 октября 2008 года»

РЕДАКТИРОВАТЬ Я решил пойти с явным отображением таблицы «многие ко многим» (со связанным интерфейсом), а затем в afterTransactionCompletion, вызвав save для родительской записи аудита (которая каскадно сохраняет в дочерние записи аудита) затем явно сохраняют интерфейс во всех дочерних таблицах сопоставления. Это не настоящая история аудита, скорее неинвазивный метод записи действий пользователя. Я рассмотрю Envers, если мне понадобится более полная история аудита на более позднем этапе.

Ответы [ 2 ]

1 голос
/ 11 ноября 2008

Похоже, что отношения между parentAuditRecord и transferauditrecord и балансом Audrecord не должны быть один ко многим. Когда я читаю то, что вы ввели, я вижу это как таблицу для каждого подкласса этой иерархии аудита, которая является отношением один к одному.

http://www.hibernate.org/hib_docs/reference/en/html/inheritance.html

Вы также можете попробовать проект Envers JBoss.

0 голосов
/ 20 ноября 2008

На уровне проектирования кажется, что чудеса со вставкой только в db будут здесь работать.

Если вы хотите сохранить его таким, каким он является сейчас (что, я уверен, вы делаете), вы можете посмотреть в Hibernate слушатели / перехватчики / события (четко определенные в документе: http://www.hibernate.org/hib_docs/v3/reference/en-US/html_single/)

Иначе, я только что посмотрел на JBoss Envers, и это также кажется довольно полезным.

...