Hibernate XML配置中使用非主键关联表的问题排查
问题分析与解决方案
问题根源
你用<join>标签的方式不对,Hibernate的<join>(对应@SecondaryTable注解)本质是基于主表主键的多表映射,它的设计逻辑是主表的主键关联从表的某个字段(默认是从表主键)。你配置里的property-ref只是指定从表用PUBLICATION_ID这个非主键字段来匹配主表的主键,而不是让主表用publikationsId这个非主键字段去关联从表,这就是为什么生成的SQL里用了GROUP_PUBLICATIONS.ID关联PUBLICATIONS.PUBLICATION_ID。
正确解决方案
针对你的遗留数据库场景,有两种靠谱的实现方式:
方案一:通过多对一关联映射PUBLICATIONS
直接在GroupPublications里映射一个到PUBLICATIONS的多对一关联,通过property-ref指定从表的关联字段,然后通过这个关联获取maxuse:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.myproject.model"> <class name="GroupPublications" table="GROUP_PUBLICATIONS"> <id name="dbId" column="ID" length="32"> <generator class="uuid" /> </id> <property name="publikationsId" column="PUBLICATION_ID" not-null="true" /> <!-- 映射到PUBLICATIONS的多对一关联 --> <many-to-one name="publication" column="PUBLICATION_ID" property-ref="publicationId" <!-- 指定从表的关联字段 --> fetch="join" <!-- 强制关联查询,避免懒加载问题 --> lazy="false"/> <many-to-one name="userGroups" column="GROUP_ID" not-null="true" cascade="save-update" /> </class> </hibernate-mapping>
然后在GroupPublications实体类里添加对应的属性和方法:
private Publication publication; // getter和setter public Publication getPublication() { return publication; } public void setPublication(Publication publication) { this.publication = publication; } // 直接获取maxuse的快捷方法 public Integer getMaxUse() { return publication != null ? publication.getMaxUse() : null; }
方案二:用Formula直接映射maxuse字段
如果不需要完整的Publication实体,只想单独获取maxuse,可以用Hibernate的formula属性直接映射:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.myproject.model"> <class name="GroupPublications" table="GROUP_PUBLICATIONS"> <id name="dbId" column="ID" length="32"> <generator class="uuid" /> </id> <property name="publikationsId" column="PUBLICATION_ID" not-null="true" /> <!-- 用子查询直接映射maxuse字段 --> <property name="maxUse" formula="(SELECT p.maxuse FROM PUBLICATIONS p WHERE p.PUBLICATION_ID = PUBLICATION_ID)" not-null="true" lazy="false"/> <many-to-one name="userGroups" column="GROUP_ID" not-null="true" cascade="save-update" /> </class> </hibernate-mapping>
这种方式不需要额外关联实体,Hibernate会自动把这个子查询拼接到主查询里,直接返回maxuse值。
内容的提问来源于stack exchange,提问作者senko
相关产品推荐
相关产品推荐

