You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate非主键关联双向关系查询时集合无法填充问题

Hibernate多对一双向关联查询集合为空问题

问题详情

  • 关联配置:EnvelopeEvent与EnvelopeProcess为多对一双向关联,ENVELOPE_EVENT表的ENVELOPE_FK字段关联ENVELOPE_PROCESS表的非主键字段ENVELOPE_ID
  • 异常表现:插入操作正常,但查询EnvelopeProcess时其events集合始终为空;Hibernate日志显示查询框架使用EnvelopeProcess的主键id作为关联查询键,与预期不符;调试发现org.hibernate.type.CollectionType的foreignKeyPropertyName值始终为null
  • 使用版本:Hibernate 5.4.27.Final

相关代码

EnvelopeProcess实体类

public class EnvelopeProcess extends AbstractEntity{

private static final long serialVersionUID = 222222L;

private String envelopeId;

private String status;

private String subject;

private Set<EnvelopeEvent> events;

public Long getQuoteId() {
    return quoteId;
}
public void setQuoteId(Long quoteId) {
    this.quoteId = quoteId;
}
public String getEnvelopeId() {
    return envelopeId;
}
public void setEnvelopeId(String envelopeId) {
    this.envelopeId = envelopeId;
}
public String getStatus() {
    return status;
}
public void setStatus(String status) {
    this.status = status;
}
public String getSubject() {
    return subject;
}
public void setSubject(String subject) {
    this.subject = subject;
}
public Set<EnvelopeEvent> getEvents() {
    return events;
}
public void setEvents(Set<EnvelopeEvent> events) {
    this.events = events;
}
//order by trigger time from latest to oldest
public List<EnvelopeEvent> getOrderedEvents(){
    return this.events.stream()
            .sorted((e1, e2) -> e2.getTriggerTime().compareTo(e1.getTriggerTime()))
            .collect(Collectors.toList());
}

public EnvelopeEvent getLatestEvent() {
    return this.getOrderedEvents().get(0);
}

}

EnvelopeProcess映射文件

<class name="com.pat.storage.entities.EnvelopeProcess" table="ENVELOPE_PROCESS" polymorphism="implicit" mutable="true" dynamic-insert="false" dynamic-update="false" >
    <cache usage="read-write" region="com.pat.storage.entities"/>
    <id name="id" type="long" unsaved-value="null" >
        <column name="ID"/>
        <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
            <param name="sequence_name">ZSEQID_ENVELOPE_PROCESS</param>
            <param name="initial_value">1</param>
            <param name="increment_size">10</param>
            <param name="optimizer">pooled-lo</param>
            <param name="value_column">next_value</param>
            <param name="force_table_use">true</param>
        </generator>
    </id>
    <version name="version" type="int" column="VERSION"/>
    <property name="envelopeId" type="string" length="255">
        <column name="ENVELOPE_ID" not-null="false" unique="false" />
    </property>
    <property name="status" type="string" length="255">
        <column name="STATUS" not-null="false" unique="false" />
    </property>
    <property name="subject" type="string" length="255">
        <column name="SUBJECT" not-null="false" unique="false" />
    </property>
    <set name="events" lazy="false" fetch="select" inverse="true"  cascade="all">
        <cache usage="read-write" region="com.pat.storage.collections"/>
        <key foreign-key="ENVELOPE_EVENT_FKC" not-null="false"   >
            <column name="ENVELOPE_FK"/>
        </key>
        <one-to-many class="com.pat.storage.entities.EnvelopeEvent" not-found="exception"/>
    </set>
    
</class>

EnvelopeEvent实体类

public class EnvelopeEvent extends AbstractEntity{

private static final long serialVersionUID = -11111L;
    
private String eventType;

private Date triggerTime;

private EnvelopeProcess envelopeProcess;

public EnvelopeProcess getEnvelopeProcess() {
    return envelopeProcess;
}

public void setEnvelopeProcess(EnvelopeProcess envelopeProcess) {
    this.envelopeProcess = envelopeProcess;
}

public String getEventType() {
    return eventType;
}

public void setEventType(String eventType) {
    this.eventType = eventType;
}

public Date getTriggerTime() {
    return triggerTime;
}

public void setTriggerTime(Date triggerTime) {
    this.triggerTime = triggerTime;
}

}

EnvelopeEvent映射文件

<class name="com.iqx.storage.entities.EnvelopeEvent" table="ENVELOPE_EVENT" polymorphism="implicit" mutable="true" dynamic-insert="false" dynamic-update="false" >
    <cache usage="read-write" region="com.iqx.storage.entities"/>
    <id name="id" type="long" unsaved-value="null" >
        <column name="ID"/>
        <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
            <param name="sequence_name">ZSEQID_ENVELOPE_EVENT</param>
            <param name="initial_value">1</param>
            <param name="increment_size">10</param>
            <param name="optimizer">pooled-lo</param>
            <param name="value_column">next_value</param>
            <param name="force_table_use">true</param>
        </generator>
    </id>
    <version name="version" type="int" column="VERSION"/>
    <property name="eventType" type="string" length="255">
        <column name="EVENT_TYPE" not-null="true" unique="false"   />
    </property>
    <property name="triggerTime" type="timestamp" precision="3">
        <column name="TRIGGER_TIME" not-null="true" unique="false"/>
    </property>
    <many-to-one name="envelopeProcess" class="com.iqx.storage.entities.EnvelopeProcess"  cascade="none" 
        foreign-key="ENVELOPE_EVENT_FKC" not-null="true" lazy="proxy" fetch="select" property-ref="envelopeId">
        <column name="ENVELOPE_FK" not-null="false"  />
    </many-to-one>
</class>

问题原因及修复方案

原因

EnvelopeProcess的集合映射未指定关联的非主键字段,Hibernate默认使用主键id作为关联查询的匹配键,与多方(EnvelopeEvent)配置的关联逻辑不一致,导致查询不到关联数据。

修复步骤

修改EnvelopeProcess映射文件中的<set>标签下的<key>节点,添加property-ref="envelopeId"属性,指定使用非主键字段envelopeId作为关联匹配字段:

<set name="events" lazy="false" fetch="select" inverse="true"  cascade="all">
    <cache usage="read-write" region="com.pat.storage.collections"/>
    <key foreign-key="ENVELOPE_EVENT_FKC" not-null="false" property-ref="envelopeId">
        <column name="ENVELOPE_FK"/>
    </key>
    <one-to-many class="com.pat.storage.entities.EnvelopeEvent" not-found="exception"/>
</set>

说明

双向关联中,多方(EnvelopeEvent)的<many-to-one>已经通过property-ref="envelopeId"指定了关联到EnvelopeProcess的非主键字段,一方(EnvelopeProcess)的集合映射必须同步配置该属性,才能保证查询时关联逻辑一致,正确加载关联的events集合数据。

内容的提问来源于stack exchange,提问作者skyman lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:37:04