Как диагностировать hibernate: Почему запрос с EntityGraph не работает?

Ссылка скопирована
1 ответ

По вводным: есть два запроса, один с использованием fetch join, второй такой-же, но вместо fetch join используется EntityGraph Запрос c fetch join выглядит так:

var builder = session.getCriteriaBuilder(); var criteriaQuery = builder.createQuery(MarketOrderPhotoItem.class); var root = criteriaQuery.from(MarketOrderPhotoItem.class); var sellerSubjectJoin = root.fetch("sellerSubject", JoinType.LEFT); sellerSubjectJoin.fetch("user", JoinType.LEFT); sellerSubjectJoin.fetch("legalEntity", JoinType.LEFT); var sales = root.fetch("sales", JoinType.LEFT); sales.fetch("payment", JoinType.LEFT); // FETCH для OneToOne root.fetch("order", JoinType.LEFT); root.fetch("marketPhoto", JoinType.LEFT); Join<MarketOrderPhotoItem, MarketPhoto> marketPhotoJoin = root.join("marketPhoto", JoinType.LEFT); Join<MarketOrderPhotoItem, MarketSale> salesJoin = root.join("sales", JoinType.LEFT); Join<MarketSale, MarketPayment> paymentJoin = salesJoin.join("payment", JoinType.LEFT); Join<MarketPayment, MarketUser> paymentUserJoin = paymentJoin.join("user", JoinType.LEFT); criteriaQuery.where( builder.and( root.get("status").in(statuses), marketPhotoJoin.get("id").in(photoId), paymentUserJoin.get("id").in(userId) ) ); criteriaQuery.orderBy(builder.asc(root.get("id"))); criteriaQuery.distinct(true);

Запрос с EntityGraph:

var builder = session.getCriteriaBuilder(); var criteriaQuery = builder.createQuery(MarketOrderPhotoItem.class); var root = criteriaQuery.from(MarketOrderPhotoItem.class); var graph = session.createEntityGraph(MarketOrderPhotoItem.class); graph.addAttributeNodes("sellerSubject", "sales", "order", "marketPhoto"); Subgraph<MarketSubject> sellerSubgraph = graph.addSubgraph("sellerSubject"); sellerSubgraph.addAttributeNodes("user", "legalEntity"); Subgraph<MarketSale> salesSubgraph = graph.addSubgraph("sales"); //Subgraph<MarketPayment> paymentSubgraph = salesSubgraph.addSubgraph("payment"); //paymentSubgraph.addAttributeNodes("user"); Join<MarketOrderPhotoItem, MarketPhoto> marketPhotoJoin = root.join("marketPhoto", JoinType.LEFT); Join<MarketOrderPhotoItem, MarketSale> salesJoin = root.join("sales", JoinType.LEFT); Join<MarketSale, MarketPayment> paymentJoin = salesJoin.join("payment", JoinType.LEFT); Join<MarketPayment, MarketUser> paymentUserJoin = paymentJoin.join("user", JoinType.LEFT); criteriaQuery.where( builder.and( root.get("status").in(statuses), marketPhotoJoin.get("id").in(photoId), paymentUserJoin.get("id").in(userId) ) ); criteriaQuery.orderBy(builder.asc(root.get("id"))); criteriaQuery.distinct(true); var typedQuery = session.createQuery(qr.criteriaQuery); typedQuery.setHint("javax.persistence.loadgraph", graph);

По вводным: если во втором запросе раскомментировать две закомментированные строки, он начинает выдавать:

query specified join fetching,
but the owner of the fetched association was not present in the select list

Сейчас ситуация такая: в чем может быть проблема? Hibernate версии 5.6.15 Находил похожие вопросы, но там либо использовался DTO-конструктор в select, либо запрос строился спрингом и он добавлял fetch к запросу с count. Не то не другое для меня не релевантно, однако ошибка такая же... Голову уже сломал. А мне нужен именно EntityGraph

По вводным: на всякий случай приведу сокращенные маппинги без лишнего:

@Entity @Table(name = "market_orderitem") @Inheritance(strategy = InheritanceType.JOINED) abstract public class MarketOrderItem { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "seller_subject", nullable = true) protected MarketSubject sellerSubject; // обратная ссылка на MarketSale @ManyToMany(mappedBy="orderItems", fetch = FetchType.LAZY) protected Set<MarketSale> sales; } @Entity @Table(name = "market_order_photo") @PrimaryKeyJoinColumn(name = "id") public class MarketOrderPhotoItem extends MarketOrderItem { @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "market_photo_id", nullable = false) private MarketPhoto marketPhoto; } @Entity @Table(name = "market_sale") public class MarketSale { // ссылка на MarketOrderItem @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "sale_items", joinColumns = {@JoinColumn(name = "sale_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "order_item_id", referencedColumnName = "id") }) protected Set<MarketOrderItem> orderItems = new HashSet<>(); @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "payment", nullable = true) private MarketPayment payment; }

По вводным: sales объявлен как many-to-many, а payment внутри sales как one-to-one. Ничего особо необычного. Единственное, что используется @Inheritance, но ведь запрос с fetch join при этом спокойно работает...

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Артём Dev Ответ

Если запрос с Hibernate EntityGraph не работает, чаще всего причина в том, что граф применен не к тому методу, конфликтует с JPQL fetch join или вы ожидаете, что EntityGraph отфильтрует данные. EntityGraph управляет стратегией загрузки связей, но не меняет условия выборки как where.

Проверьте базовые вещи: имя графа, тип графа, названия атрибутов и то, что связь действительно является полем entity. Для Spring Data JPA пример выглядит так:

@EntityGraph(attributePaths = {"author", "comments"})
Optional&lt;Post&gt; findById(Long id);

@EntityGraph(attributePaths = {"author", "comments"}) Optional&lt;Post&gt; findById(Long id);

Если используете named graph:

@NamedEntityGraph(
    name = "Post.withAuthor",
    attributeNodes = @NamedAttributeNode("author")
)
@Entity
public class Post {
    // ...
}

@NamedEntityGraph( name = "Post.withAuthor", attributeNodes = @NamedAttributeNode("author") ) @Entity public class Post { // ... }

Частые ошибки:

  • указали имя колонки вместо имени Java-поля;
  • применили EntityGraph к native query, где он не работает так же, как с JPQL;
  • ожидаете загрузку nested-связей без subgraph;
  • смешали fetch join и EntityGraph, получив неожиданный SQL;
  • смотрите объект после закрытия session и ловите LazyInitializationException.

Для диагностики включите SQL-логирование и посмотрите, какие join/select реально выполняются:

spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE

spring.jpa.show-sql=true logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.orm.jdbc.bind=TRACE

Если graph применился, вы увидите дополнительные join или отдельные select для нужных связей. Если SQL не изменился, граф не был применен: проверьте repository method, query hints и версию Hibernate. Если изменился, но данные всё равно lazy, значит вы смотрите не ту связь или доступ происходит уже вне persistence context. В сложных случаях проще явно написать JPQL с fetch join для конкретного запроса.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно