У меня есть проверенный объект A. Объект A содержит поле «имя» и набор объектов B (аннотированных как отношение «многие ко многим»). Я создал экземпляр A, определил имя, коллекцию сущностей B и сохранил все это в БД. Это ревизия №1. Затем я изменил имя A и обновил его в БД. Это ревизия №2. Я использую следующий метод, чтобы получить все объекты класса A в ревизии № 2.
List<A> list = getAuditReader().createQuery().forEntitiesAtRevision(A.class, 2)
.add(AuditEntity.revisionNumber().eq((int) revisionId)).getResultList();
Я получаю объект A в ревизии № 2, но Envers также извлекает набор сущностей B, связанных с этой A, из ревизии № 1. Вот пример запроса, используемого Энверсом:
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id
AND b_aud.rev=(SELECT max(b_aud2.rev)) FROM b_aud AS b_aud2 WHERE b_aud2.rev<=2 AND b_aud.id=b_aud2.id)
AND a_b_aud.rev=(SELECT max(a_b_aud2.rev)) FROM a_b_aud AS a_b_aud2 WHERE a_b_aud2.rev<=2 AND a_b_aud.a_id=a_b_aud2.a_id AND a_b_aud.b_id=a_b_aud2.b_id)
Но на самом деле мне нужен NULL как набор сущностей B, если для него не было изменений в ревизии № 2 (из-за проблем с производительностью).
В этом запросе есть два подзапроса. А если у нас есть более одной коллекции сущностей, связанных с A (C, D, E, F) и около 100 тысяч строк для каждого b_aud и a_b_aud, запрос выше занимает много времени. Я определил сущность B как не проверенную (т.е. не добавил аннотацию @Audited в B) и определил отношение A B следующим образом:
@ManyToMany
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@JoinTable(name = "a_b", joinColumns = @JoinColumn(name = a_id))
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public Set<B> getBs();
Он исправляет первый SUBSELECT. Но я не могу найти стандартное решение, чтобы не запрашивать B, если оно не существует для запрошенной версии (в моем случае № 2). Таким образом, запрос должен выглядеть так:
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id b_aud.rev=2 AND a_b_aud.rev=2
Единственное решение, которое я нашел, - это использовать собственный SQL-запрос и выполнять его с использованием шаблона hibernate. Затем преобразуйте значения результата в объект A с помощью ResultTransformer.
Может ли кто-нибудь помочь с этой проблемой? Есть ли стандартная конфигурация/аннотация, которую мне нужно добавить, чтобы избежать второго SUBSELECT?