OpenJpa中Parent如何单向关联同Plant的二级子实体GrandChild
用OpenJPA实现Parent与GrandChild的单向关联(按plant属性匹配)
核心思路
通过在Parent实体中直接定义指向GrandChild的单向关联,利用JPA标准注解或OpenJPA扩展特性,过滤出plant属性与当前Parent完全匹配的GrandChild记录,无需通过Child实体中转查询。
方案一:标准JPA单向关联(推荐)
使用@OneToMany结合@JoinColumnsOrFormulas,直接通过关联条件绑定Parent与GrandChild的关系,同时匹配plant属性。
实体代码实现
- Parent实体
import javax.persistence.*; import java.util.List; @Entity public class Parent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String plant; // Parent的plant属性 // 单向关联GrandChild,仅匹配plant相同的记录 @OneToMany(fetch = FetchType.LAZY) @JoinColumnsOrFormulas({ // 通过子查询关联到Child的parent_id,再关联到GrandChild的child_id @JoinColumnOrFormula(formula = @JoinFormula( value = "(SELECT c.id FROM Child c WHERE c.parent_id = id)", referencedColumnName = "child_id" )), // 匹配Parent与GrandChild的plant属性 @JoinColumnOrFormula(column = @JoinColumn( name = "plant", referencedColumnName = "plant" )) }) private List<GrandChild> matchingGrandChildren; // getter、setter省略 }
- Child实体
import javax.persistence.*; import java.util.List; @Entity public class Child { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne @JoinColumn(name = "parent_id") private Parent parent; @OneToMany(mappedBy = "child") private List<GrandChild> grandChildren; // getter、setter省略 }
- GrandChild实体
import javax.persistence.*; @Entity public class GrandChild { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne @JoinColumn(name = "child_id") private Child child; private String plant; // GrandChild的plant属性 // getter、setter省略 }
方案二:自定义NamedQuery查询
如果标准关联方式不适用,可在Parent中定义命名查询,直接获取符合条件的GrandChild。
实现代码
import javax.persistence.*; import java.util.List; @Entity @NamedQuery( name = "Parent.getMatchingGrandChildren", query = "SELECT gc FROM GrandChild gc " + "JOIN gc.child c " + "JOIN c.parent p " + "WHERE p.id = :parentId AND gc.plant = p.plant" ) public class Parent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String plant; // 调用命名查询获取结果 public List<GrandChild> getMatchingGrandChildren(EntityManager em) { return em.createNamedQuery("Parent.getMatchingGrandChildren", GrandChild.class) .setParameter("parentId", this.id) .getResultList(); } // getter、setter省略 }
方案三:OpenJPA扩展@Filter注解
利用OpenJPA的@Filter特性动态过滤关联数据,仅加载plant匹配的GrandChild。
实现代码
import org.apache.openjpa.persistence.Filter; import javax.persistence.*; import java.util.List; @Entity public class Parent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String plant; @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "child_id", insertable = false, updatable = false) @Filter(name = "plantMatch", condition = "plant = :parentPlant") private List<GrandChild> matchingGrandChildren; // 启用过滤器(需在事务内调用) public void enablePlantFilter(EntityManager em) { org.apache.openjpa.persistence.OpenJPAEntityManager openJpaEm = org.apache.openjpa.persistence.OpenJPAPersistence.cast(em); openJpaEm.getFetchPlan().addFilter("plantMatch", "parentPlant", this.plant); } // getter、setter省略 }
注意事项
- 优先选择方案一,符合JPA标准,无需额外代码调用即可直接访问关联集合;
- 确保Parent与GrandChild的
plant字段类型、长度一致,避免匹配异常; - 使用LAZY加载时,需在事务范围内访问关联集合,防止懒加载错误;
- 方案三依赖OpenJPA扩展特性,移植性较差,仅适合单一使用OpenJPA的项目。
内容的提问来源于stack exchange,提问作者Mohammad Naim Dahee
相关产品推荐
相关产品推荐

