Задать вопрос
@Arlekcangp
Разработчик, Лид, Архитектор ПО

Hibernate: Почему запрос с EntityGraph не работает?

Есть два запроса, один с использованием 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 при этом спокойно работает...
  • Вопрос задан
  • 69 просмотров
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы