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
相关产品推荐
相关产品推荐

