在 Hibernate HQL 中,我如何过滤以我的主 Table 为父级的加入 Table 的结果?

In Hibernate HQL, how do i filter the results of a joined Table parented to my main Table?

我有一个名为 "PN" 的父 Table,它的实体中包含另一个实体 "PnDett" 的列表,该实体与第一个 table 相关。 我想执行一个查询,该查询将根据我的 where 条件提供 PN 列表,但也会根据 where 条件过滤 "PnDett" 列表。 我怎样才能做到这一点?

这是 PN 映射:

@Entity
@Table(name = "PN")
public class Pn implements java.io.Serializable {

private static final long serialVersionUID = 2556879508428749494L;

@Id
@Column(name="ID_PN", unique = true, nullable = false)
private BigDecimal idPN;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_DOC")
private Date dataDoc;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_COMP_BANC")
private Date dataCompBanc;

@Column(name="STATO_PN")
private String statoPN;

@Column(name="TESTO_TESTATA")
private String testoTestata;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_INVIO_SAP")
private Date dataInvioSap;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_INS")
private Date dataIns;

@Column(name="ID_UTENTE_AGG")
private BigDecimal idUtenteAgg;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_CONTABILE")
private Date dataContabile;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_REND_INTEGR")
private Date dataRendIntegr;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="DATA_AGG")
private Date dataAgg;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "pn")
private Set<PnDett> pnDetts = new HashSet<>(0);

这是 PnDett 映射:

@Entity
@Table(name = "PN_DETT")
public class PnDett implements java.io.Serializable {
private static final long serialVersionUID = 2556879508428749494L;

@Id
@Column(name="ID_PN_DETT", unique = true, nullable = false)
private BigDecimal idPNDett;

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="ID_PN", nullable=false)
private Pn pn;

@OneToOne
@JoinColumn(name="ID_DOM_TIPO_SCRITTURA")
private DomTipoScrittura domTipoScrittura;

@Column(name="TIPO_DOCUMENTO")
private String tipoDocumento;

@Column(name="ID_CALCOLO")
private String idCalcolo;


@Column(name="CONTO_COGE")
private String contoCoge;

@Column(name = "IMPORTO_AVERE")
private BigDecimal importoAvere;

@Column(name = "IMPORTO_DARE")
private BigDecimal importoDare;

@OneToOne
@JoinColumn(name="ID_UTENTE")
private Utente utente;

@Column(name = "DATA_INS")
private Date dataIns;

@Column(name = "TIPO_DETTAGLIO")
private String tipoDettaglio;

@Column(name = "SE_CANC")
private Integer seCancellato;

在 HQL 中,我写了这个查询 "select * from Pn firstNote where firstNote.dataContabile = (a param i put myself, in this case 20 april 2020) and firstNote.pnDetts.seCancellato = (a param i put myself, in this case 0) and firstNote.pnDetts.importoDare <> 0 or firstNote.pnDetts.importoAvere <> 0"

坦率地说,结果一团糟。我的 PN table 中只有两行在 2020 年 4 月 20 日设置了参数 dataContabile,但我得到了 18 个结果,结果是一个 Object[],它以某种方式包含两个实体。在 PN 对象中,我确实过滤了 pnDetts 列表以匹配我正在搜索它们的日期,但其他过滤器甚至不起作用。我该如何解决这个问题?理想情况下,我的结果应该是两个 PN 对象的列表,这些对象过滤了 pnDetts 列表,但我不知道如何实现。

编辑: 好的,我做了一个 SQL 查询,发现与该日期相关的具有 importoDare <> 0 或 importoAvere<>0 的 PnDett 行正好是 18,这就是为什么我得到 18 组对象 [] .但是我怎么能只有两个 PN 对象,而不是筛选内部列表呢?

为了使过滤器工作,我们可以使用 fetch,这将确保初始查询获取所有需要的数据。

select * from Pn firstNote join fetch firstNote.pnDetts pnd where firstNote.dataContabile = :param1 and pnd.seCancellato = :param2 and pnd.importoDare <> 0 or pnd.importoAvere <> 0

如 Vishnu 所述,您可以使用 join fetch,但这种方法存在很多问题。由于查询的结果是托管实体,因此过滤集合是有问题的。当您的事务完成时,过滤掉的元素可能会被删除,因此在这样的查询之后立即分离所有实体非常重要,例如查看 entityManager.clear().

如果您还想要 Pn 个具有空 pnDetts 的对象,因为没有任何匹配项,那么您不走运 join fetch 并且必须使用像这样的普通连接:

SELECT firstNote, pnd
FROM Pn firstNote 
LEFT JOIN firstNote.pnDetts pnd 
   ON pnd.seCancellato = :param2 AND pnd.importoDare <> 0 
   OR pnd.importoAvere <> 0
WHERE firstNote.dataContabile = :param1

这是一个标量查询,它将 return Object[] 因此您必须手动收集列表。