Envers @ManyToMany подзапрос

У меня есть проверенный объект 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?


person rholovakha    schedule 07.02.2013    source источник


Ответы (1)


В Envers нет возможности не загружать связанные объекты по запросу. Однако это не означает, что объекты B всегда загружаются лениво (независимо от аннотаций отношения), поэтому, если вы не хотите выполнять запрос, который их загружает, просто не обращайтесь к этому полю.

Если вам нужна более высокая производительность чтения, вы также можете ознакомиться со стратегией аудита достоверности, см. http://docs.jboss.org/hibernate/core/4.1/devguide/en-US/html/ch15..html#d5e4085. Он быстрее читает, но медленнее пишет.

person adamw    schedule 08.02.2013