Есть два запроса, один с использованием 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 при этом спокойно работает...