Spring JPA оптимизирует транзитивную загрузку @ManyToOne

0

В моем проекте у меня есть три сущности:

@Entity
public class A {
    @Id
    private int id;
}

@Entity
public class B {
    @Id
    private int id;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private A a;
}

@Entity
public class C {
    @Id
    private int id;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private B b;
}

Как вы можете видеть, C имеет tansitive ManyToOne-Relationship с A Теперь я хочу получить все C с конкретным A используя мой JpaRepository:

public interface CRepository extends JpaRepository<C, Integer> {
    List<C> findAllByBA(A a);
}

Это приводит к следующему запросу Hibernate sql (что хорошо):

Hibernate: выберите... из c c0_ cross join b b1_, где c0_.b_id = b1_.id и b1_.a_id =?

Но потом я получаю еще один запрос для каждого отдельного B (который может быть несколько тысяч, так что это не нормально):

Hibernate: выберите... из b b0_ internal присоедините a1_ к b0_.a_id = a1_.id где b0_.id =?


Очевидно, что это можно решить с помощью единственного соединения, используя все три таблицы. Но как мне сказать Hibernate сделать это, не теряя удобства абстракции с JpaRepository?

Теги:
spring
hibernate
jpa

1 ответ

1
Лучший ответ

Дополнительные, нежелательные запросы вызваны тем, что ассоциация нетерпеливо. Чтобы избежать загрузки B, вы должны сделать объединение ленивым:

@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)

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

@Query("select c from C c left join fetch c.b where c.b.a = ?") 
  • 0
    «Я обычно делаю каждую ассоциацию ленивой». Нет! Это действительно плохая идея, и здесь нет смысла, потому что вы можете использовать объединение, даже если отношения EAGER. Если вы сделаете все ассоциации LAZY, у вас будет много кода инициализации. Кроме того, LAZY работает только для необязательных ссылок ToOne.
  • 0
    Извините, не решение для меня. Я использую сущности в пользовательском интерфейсе vaadin и не хочу загрязнять пользовательский интерфейс сеансами гибернации.
Показать ещё 9 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню