Criteria API:列表的获取返回重复的主实体 [英] Criteria API: Fetch of a list returns repeated main entity

查看:81
本文介绍了Criteria API:列表的获取返回重复的主实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下实体;工单包含一组0,N个工作订单:

I have the following Entities; Ticket contains a set of 0,N WorkOrder:

@Entity
public class Ticket {

  ...

  @OneToMany(mappedBy="ticket", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  private List<WorkOrder> workOrders = null;

  ...
}

@Entity
public class WorkOrder {
  ...
  @ManyToOne
  @JoinColumn(nullable = false)
  private Ticket ticket;
}

我正在装入票证并获取属性.所有的0,1属性都没有问题.对于workOrder,我使用了此答案来获取以下代码.

I am loading Tickets and fetching the attributes. All of the 0,1 attributes present no problem. For workOrders, I used this answer to get the following code.

CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<Ticket> criteriaQuery = criteriaBuilder
  .createQuery(Ticket.class);
Root<Ticket> rootTicket = criteriaQuery.from(Ticket.class);

ListAttribute<? super Ticket, WorkOrder> workOrders =
  rootTicket.getModel().getList("workOrders", WorkOrder.class);
rootTicket.fetch(workOrders, JoinType.LEFT);

    // WHERE logic
    ...

criteriaQuery.select(rootTicket);
TypedQuery<Ticket> query = this.entityManager.createQuery(criteriaQuery);
return query.getResultList();

结果是,在一个查询中应返回1张带有5个workOrders的工单,我正在检索同一张工单5次.

The result is that, in a query that should return me 1 Ticket with 5 workOrders, I am retrieving the same Ticket 5 times.

如果我仅使workOrders成为Eager Fetch并删除该提取代码,则它应能正常工作.

If I just make the workOrders an Eager Fetch and delete the fetch code, it works as it should.

有人可以帮助我吗?预先感谢.

Can anyone help me? Thanks in advance.

更新:

一种解释,说明为什么我不仅仅对JB Nizet的回答感到满意(即使最终可以奏效).

One explanation about why I am not just happy with JB Nizet's answer (even if in the end it works).

当我只是渴望建立关系时,JPA正在检查与我懒惰时完全相同的数据,并将fetch子句添加到Criteria/JPQL中.当我为Criteria查询定义ListAttribute时,各个元素之间的关系也很清楚.

When I just make the relationship eager, JPA is examining exactly the same data that when I make it lazy and add the fetch clause to the Criteria / JPQL. The relationships between the various elements is also clear, as I define the ListAttribute for the Criteria query.

有某种合理的解释是因为两种情况下JPA均不会返回相同的数据?

There is some reasonable explanaition for the reason that JPA does not return the same data in both cases?

赏心悦目的更新:尽管JB Nizet的回答确实解决了这个问题,但我仍然发现它毫无意义,因为给出了两个具有相同含义的操作(获取Ticket并在ticket.workOrders中获取所有WorkOrder"),急于加载的文件无需进一步更改,而指定获取则需要DISTINCT命令

UPDATE FOR BOUNTY: While JB Nizet's answer did solve the issue, I still find it meaningless that, given two operations with the same meaning ("Get Ticket and fetch all WorkOrder inside ticket.workOrders"), doing them by an eager loading needs no further changes while specifying a fetch requires a DISTINCT command

推荐答案

  1. 预先加载和获取联接之间有区别.急于加载并不意味着数据已在同一查询中加载.这只是意味着它会立即加载,尽管还会有其他查询.

  1. There is a difference between eager loading and fetch join. Eager loading doesn't mean that the data is loaded within the same query. It just means that it is loaded immediately, although by additional queries.

条件始终会转换为SQL查询.如果指定联接,它将在SQL中联接.根据SQL的性质,这也将根实体的数据相乘,从而获得效果. (请注意,您多次获得同一实例,因此根实体不会在内存中相乘.)

The criteria is always translated to an SQL query. If you specify joins, it will be join in SQL. By the nature of SQL, this multiplies the data of the root entity as well, which leads to the effect you got. (Note that you get the same instance multiple times, so the root entity is not multiplied in memory.)

有几种解决方法:

  • 使用distinct(true)
  • 使用不同的根实体转换器(.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).
  • 当您不需要按子属性进行过滤时,请避免加入连接
  • 当您需要按子属性进行过滤时,请按子查询(DetachedCriteria)进行过滤.
  • 通过使用批量大小
  • use distinct(true)
  • Use the distinct root entity transformer (.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).
  • When you don't need to filter by child properties, avoid the join
  • When you need to filter by child properties, filter by a subquery (DetachedCriteria).
  • Optimize the N+1 problem by using batch-size

这篇关于Criteria API:列表的获取返回重复的主实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆