当前位置: 首页 > 知识库问答 >
问题:

JPA Hibernate-父表和子表之间的内部联接

郭阳泽
2023-03-14

编辑(完全重新制定的方法):

我试图在一个新项目中推广JPA的使用,但我正在努力解决一个据说微不足道的问题:两个表(父表和子表)之间的内部连接。

我只提供必要的信息,其余的都不提供。如果需要,请随时询问更多信息。有两个表LANGUAGE和MESSAGE\u RESOURCE,其中父表是LANGUAGE(主键ID\u LANGUAGE),子表有一个指向父表的外键(也称为ID\u LANGUAGE)。

语言(父)类:

@Entity
@Table(name = "PF_LANGUAGE")
public class Language {
    @Id
    @Column(name = "ID_LANGUAGE", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int idLanguage;

    @OneToMany(mappedBy="language",targetEntity=MessageResource.class, fetch=FetchType.EAGER)
    private Collection<MessageResource> messageResources;
}

子类:

@Entity
@Table(name = "PF_MESSAGE_RESOURCE")
public class MessageResource {

    @Id
    @Column(name = "ID_MESSAGE_RESOURCE", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int idMessageResource;

    @ManyToOne(optional=false)
    @JoinColumn(name="ID_LANGUAGE")
    private Language language;
}

我正在使用命名查询获取结果:

entityManager.createNamedQuery("select l, r from Language l join l.messageResources r");

这将生成一个结果对象数组,其中每个条目都包含一种语言MessageResource pair。问题是,这是在单独的查询中完成的。

我可以在调试输出中看到,第一个查询是两个表之间的内部联接,在输出中包含两个表中的列,因此这应该足够了。但是JPA正在执行另外两个查询(语言记录的数量),再次获取每个父表的子表值,这应该是不必要的。

足以获取所有数据的第一个查询:

select
   language0_.ID_LANGUAGE as ID1_5_0_,
   messageres1_.ID_MESSAGE_RESOURCE as ID1_4_1_,
   language0_.CODE as CODE5_0_,
   language0_.DATE_INS  as DATE3_5_0_,
   language0_.DESCRIPTION  as DESCRIPT4_5_0_,
   messageres1_.DATE_INS  as DATE2_4_1_,
   messageres1_.KEY as KEY4_1_,
   messageres1_.ID_LANGUAGE as ID5_4_1_,
   messageres1_.VALUE as VALUE4_1_ 
from
   PF_LANGUAGE language0_ 
inner join
   PF_MESSAGE_RESOURCE messageres1_ 
on language0_.ID_LANGUAGE=messageres1_.ID_LANGUAGE

在第一次内部联接之后,还会对数据库运行以下两个冗余查询(它们对每个语言表记录运行一次):

select
    messageres0_.ID_LANGUAGE as ID5_5_1_,
    messageres0_.ID_MESSAGE_RESOURCE as ID1_1_,
    messageres0_.ID_MESSAGE_RESOURCE as ID1_4_0_,
    messageres0_.DATE_INS  as DATE2_4_0_,
    messageres0_.KEY as KEY4_0_,
    messageres0_.ID_LANGUAGE as ID5_4_0_,
    messageres0_.VALUE as VALUE4_0_ 
from
    PF_MESSAGE_RESOURCE messageres0_ 
where
    messageres0_.ID_LANGUAGE=?

我需要消除JPA生成的两个冗余的额外查询。第一个内部联接足以获取所有数据。

这个需要帮助。有线索吗?

共有3个答案

孟璞
2023-03-14

我不太明白,在这种情况下,您为什么希望内部连接。

在manytone中,表示每个消息资源都必须有一种语言,但这并不意味着每个语言都必须至少有一种消息资源,因此,在这种情况下,加载语言时的左连接是正确的-,您加载的语言可能没有与之关联的消息资源。

编辑:如果数据库中存在具有给定id的对象,则查找()的目的是加载该对象。如果您想要语义不同的内容(例如,要加载至少有一个MessageResource的所有语言),您需要为其编写查询,例如从语言中选择l加入l.messageResources。

邓丰
2023-03-14

我不确定这是否是实际的解决方案,但我在急切获取方面的经验很差。在某种程度上,它总是吸引人,这是我没有料到的。

您的查询很奇怪,您同时选择语言和消息资源是没有意义的

您可以尝试:

删除fetch=FetchType。在语言与MessageResource的关系中进行渴望,并将查询更改为

select l from Language l join fetch l.messageResources where ....

它应该在一个SQL中为您提供语言和该实例的聚合消息资源。

有些离题,我想知道你为什么有MessageResource。语言可插入=false,可更新=false。在语言中,这似乎是矛盾的,您指定了此字段映射的关系,但现在将其设置为不可插入/不可更新。

乐正宜人
2023-03-14

尝试更改fetch=FetchType。对于要获取的messageResources,渴望获取=FetchType。LAZY因为您是显式加入的,所以将FetchType更改为LAZY可能会有所帮助。

 类似资料:
  • 问题内容: 这可能是一个愚蠢的问题,但可能会为联接在内部的工作方式提供一些启示。 假设我有一个大表和一个小表(100K行vs. 100行)。 以下两个选项在速度方面是否会有任何差异? 注意,唯一的区别是表的连接顺序。 我意识到不同的SQL语言之间的性能可能会有所不同。如果是这样,MySQL与Access相比如何? 问题答案: 不,顺序无关紧要。 几乎所有的RDBMS(例如MS Access,MyS

  • 问题内容: 我有一个数据表(AmenityData),该表的一列包含postalsectors,例如E14 7 我也有一个Excel电子表格,其中包含邮政区的列表,例如E14 我需要从AmenityData表中获取所有数据,该表中的邮政地区类似于邮政部门,例如WHERE [PostalDistricts] +’%’LIKE [PostalSector]。 我目前正在使用的代码不会出现错误,而是什么

  • 问题内容: 问题 我需要更好地了解有关何时可以在子查询中引用外部表以及何时(以及为什么)不适当的请求的规则。我在尝试重构的Oracle SQL查询中发现一个重复项,但是当我尝试将引用的表转换为分组的subQuery时遇到了问题。 以下语句可以正常工作: 不幸的是table2有时会有重复的记录,因此在将t2加入t1之前,我需要先对其进行汇总。但是,当我尝试将其包装在子查询中以完成此操作时,SQL引擎

  • 问题内容: 我的本地Postgres数据库中有3个表: 在运行时,我会知道。我需要运行SQL来更新与此项目关联的内容,因此类似: 我可能必须执行某种嵌套或在子句中进行操作,但不确定如何执行此操作。提前致谢! 编辑 : 假设我有一条具有以下值的记录: 相应的(id = 23)具有以下值: 在运行时,我只有(458)。我需要在单个UPDATE语句中查找对应的(23)并将其更改为。 问题答案:

  • 问题内容: 我似乎无法内部连接到教师表以获得名字和姓氏。 我收到的错误消息是 问题答案: 以下错误是因为您未指定列: Msg 8156,第16级,状态1,第3行 为“ MaxBookingDays”多次指定了“ ID”列。 因此,我将您的查询稍作更改,如下所示:

  • 问题内容: 我准备了一个 小提琴 来演示这个问题。 我想要一种在删除子记录时将其删除到CASCADE到父记录的方法。 例如: 这应该级联到父表并删除记录。 问题答案: 外键仅在另一个方向上起作用:从父级到子级级联删除,因此,当删除父级(引用)记录时,所有子级(引用)记录也会被删除。 如果是1:1关系,则可以创建双向外键关系,其中一侧为,而两侧均为级联。 否则,您将需要在子表上创建一个触发器,以在没