У меня есть таблица Product
со столбцом имени, и я хотел бы сохранить историю изменений имени в таблице ProductHistory
. (В таблице Product
также есть несколько других столбцов. Мне не нужно отслеживать изменения данных для этих столбцов.)
Мое приложение будет использовать ProductHistory
таблицу, когда пользователь запрашивает запуск отчета за заданную дату. В отчете должны быть указаны названия продуктов на дату отчета.
Я использую Spring Boot 1.5.2 и включаю зависимость JPA от Spring Boot Starter Data. Я планирую использовать Hibernate Envers в рамках Spring Data JPA, чтобы помочь в достижении моей цели. Я прочитал этот документ но не знаю, как указать дату вступления в силу ProductHistory
.
Я включил аудит JPA:
@Configuration
@EnableJpaRepositories("com.example.repository")
@EnableJpaAuditing
public class DatabaseConfig {
//config items
}
Использование документа в качестве справки у меня должна быть сущность как:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@LastModifiedDate
private Date effectiveDateUtc;
private String name;
//other fields corresponding to othercols
}
Но effectiveDateUtc
не является полем / столбцом Product
. Как мне указать, что effectiveDateUtc
является собственностью ProductHistory
?
Обновить
Мне не удалось найти способ выполнить вышеуказанное, используя возможности аудита Spring Data JPA. Однако, используя ответ, опубликованный Naros / Hibernate envers, я смог достичь своих целей.
Помимо того, что опубликовал Naros, вот что еще я обнаружил, что мне нужно сделать, чтобы это работало с моим приложением Spring:
Добавьте необходимые jar-файлы в мою сборку gradle:
compile('org.hibernate:hibernate-envers:5.2.10.Final')
compile('org.hibernate:hibernate-core:5.2.10.Final')
compile('joda-time:joda-time:2.1')
Создал необходимую схему в БД.
Я также настроил тестовый пример интеграции, чтобы убедиться, что я могу выполнять запросы типа отчета по данным ревизии. Для этого мне нужно было получить диспетчер сущностей и передать его фабрике считывателя аудита:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=ProductDataApplication.class)
public class ProductRepositoryTest {
@PersistenceContext
private EntityManager entityManager;
@Test
@Transactional
public void testEnversQuerying() {
AuditReader ar = AuditReaderFactory.get(entityManager);
Product revisions = ar.find(Product.class, 1L, new Date());
// assert code
}
}
Как предположил Нарос, мне также нужно сохранить идентификатор пользователя, связанный с ревизией. Я сделал это следующим образом:
public class UserRevisionListener implements RevisionListener {
@Override
public void newRevision(Object revisionEntity) {
UserRevision revision = (UserRevision) revisionEntity;
if (SecurityContextHolder.getContext().getAuthentication() == null ||
SecurityContextHolder.getContext().getAuthentication().getName() == null) {
revision.setModifiedBy("system");
} else {
revision.setModifiedBy(SecurityContextHolder.getContext().getAuthentication().getName());
}
}
}