简体   繁体   中英

Join fetching with FetchMode.SELECT using Hibernate and JPA2 Criteria

I'm using JPA2 Criteria API with Hibernate. The simplified database schema is as follows

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
    private Set<OrderItem> items = new LinkedHashSet<>();

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
    private Set<OrderTransaction> transactions = new LinkedHashSet<>();

Corresponding OrderItem and OrderTransaction have @ManyToOne relation with Order

I'm using following query to fetch Order with all of its descendants

public List<Order> findByIds(Collection<Long> ids) {
        if (ids.isEmpty()) return Collections.emptyList();
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Order> query = builder.createQuery(Order.class);
        Root<Order> root = query.from(Order.class);

        root.fetch("items", JoinType.LEFT);
        root.fetch("transactions", JoinType.LEFT);

        Predicate whereId = root.get("id").in(ids);

        TypedQuery<Order> typedQuery = entityManager.createQuery(
                query
                        .select(root)
                        .where(whereId)
                        .distinct(true)
        );
        return typedQuery.getResultList();
    }

The resulting query is

select distinct order0_.id            as id1_75_0_,
                items1_.order_id      as order_i28_74_0__,
                items1_.id            as id1_74_0__,
                transactio2_.order_id as order_i13_80_1__,
                transactio2_.id       as id1_80_1__
from Order order0_
         left outer join OrderItem items1_ on order0_.id = items1_.order_id
         left outer join OrderTransaction transactio2_ on order0_.id = transactio2_.order_id
where order0_.id in (?, ?)

I'm trying to achieve fetch join but with multiple queries. I'm expecting to get entirely loaded entity out of the Repository. Lazy loading is not an option. So expected output is 3 queries, one for fetching Order , and the other two for OrderItem and OrderTransaction . Batching would be beneficial but it is not necessary.

What I tried so far

  1. Adding @Fetch(FetchMode.SELECT) to each OneToMany . It didn't change anything. I think It works in pair with lazy loading, not with join fetch I'm doing.
  2. Removing join fetches from the query. It lead to 1+n problem with lazy loading, but as I told lazy loading is not an option.

Solutions I came up with

  1. Manually refactoring hundreds of queries to add additional manual fetches. It is doable but maybe not necessary.
  2. Extending CriteriaBuilder API with custom implementation in order to replace each join fetch with additional query.

Is there Hibernate solution for this problem?

Came up with satisfying solution.

I'm using @Fetch(FetchMode.SUBSELECT) . I remove all the OneToMany fetches from the query with a custom utility, and initialize collections via reflection. That way I do get 3 queries and entities are entirely initialized leaving the Repository

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM