使用 EntityGraph 进行具有可选 ManyToOne 关系的查询

问题描述 投票:0回答:1

我有一个 Hibernate 实体,与另一个实体具有可选关系:

@NamedEntityGraph(
    name = "expense-for-frontend",
    attributeNodes = {
      @NamedAttributeNode("shipment"),
    })
@Entity
public class Expense {
  ...
  @ManyToOne(fetch = FetchType.LAZY, optional = true)
  private Shipment shipment;
  ...
}

我希望能够加载

Expense
,无论他们是否有
Shipment
,但如果他们确实有货物,则应该预先加载回来,以避免数据库往返。存储库有一个类似于以下内容的查询:

  @EntityGraph("expense-for-frontend")
  @Query(
      """
      SELECT e
      FROM Expense e
      LEFT JOIN Shipment s ON e.shipment.id = s.id
      WHERE (:status IS NULL OR e.status = :status)
      """)
  List<PaidShipmentExpenseBE> findAllFilteredShipmentExpensesWithPayment(
      @Param("status") @Nullable VendorPaymentStatus status);

执行的SQL是:

select eb1_0.id, ...
from expense eb1_0
join shipment s1_0 on s1_0.id=eb1_0.shipment_id 
left join shipment sb1_0 on sb1_0.tenant_id = ? and eb1_0.shipment_id=sb1_0.id
...

针对

shipment
的内连接由
@NamedAttributeNode("shipment")
中的
EntityGraph
添加,并且 s1_0 在查询的其余部分中不使用。因为它添加了内部联接,所以在使用该功能时我无法检索任何未链接到发货的费用
EntityGraph

我找不到任何方法来更改 EntityGraph 以允许可选的多对一关系。

  • 我不想从 EntityGraph 中删除
    @NamedAttributeNode("shipment")
    ,因为这会导致每行费用有额外的数据库往返,而且费用有很多。
  • 我找不到任何方法来配置
    NamedAttributeNode
    来告诉它生成左连接。

这似乎是一种非常常见的情况,并且列的可为空性是通过标准 jakarta 持久性注释

@ManyToOne(fetch = FetchType.LAZY, optional = true)
公开的,因此我假设
EntityGraph
可以正确处理这种情况。我是不是错过了什么?

java hibernate spring-data-jpa hibernate-mapping entitygraph
1个回答
0
投票

您的查询有误。最有可能的是,您想写

e.shipment.id = s.id
,而不是
e.shipment_id = s.id
,但这并不重要, 因为在您的查询中,关系
LEFT JOIN Shipment s ON e.shipment.id = s.id
是多余的。您已经使用
@ManyToOne
注释描述了 Expense 和 Shipment 实体之间的关系,因此 Hibernate 进行了第一个连接。通过向查询添加另一个关系,您迫使 Hibernate 进行另一个连接。但为了避免在 sb1_0.id 表达式中访问
NULL
,它必须使用内连接而不是通常的左连接来获取
sb1_0
。因此,只需从查询中删除
LEFT JOIN Shipment s ON e.shipment.id = s.id
即可。

另外,在

@ManyToOne(fetch = FetchType.LAZY, optional = true)
表达式中,optinal默认为true,所以不需要指定。

© www.soinside.com 2019 - 2024. All rights reserved.