JPA单表继承场景下使用Criteria按关联子类属性查询方法
JPA单表继承关联子类属性的Criteria查询实现
问题核心原因
当前直接关联到父类PartnerEntity的Join对象,仅能访问父类中定义的属性,无法直接获取Entity1、Entity2子类特有的嵌入属性category,强行调用get("category")会抛出属性不存在的异常。
正确实现代码
在已有的初始代码基础上,使用JPA Criteria提供的treat()方法做继承类型向下转型,分别匹配两个存在category属性的子类即可,补全代码如下:
CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<MoralEntity> query = cb.createQuery(MoralEntity.class); Root<MoralEntity> root = query.from(MoralEntity.class); Join<MoralEntity, PartnerEntity> moralPartnerJoin = root.join("partner"); // 把父类Join向下转型为包含category属性的两个子类 Join<MoralEntity, Entity1> e1PartnerJoin = cb.treat(moralPartnerJoin, Entity1.class); Join<MoralEntity, Entity2> e2PartnerJoin = cb.treat(moralPartnerJoin, Entity2.class); // 构建查询条件:任意一个子类的category.code匹配"ABC"即符合要求 Predicate matchCondition = cb.or( cb.equal(e1PartnerJoin.get("category").get("code"), "ABC"), cb.equal(e2PartnerJoin.get("category").get("code"), "ABC") ); // 组装查询并执行 query.select(root).where(matchCondition); List<MoralEntity> resultList = em.createQuery(query).getResultList();
实现原理说明
cb.treat()是JPA 2.1开始提供的标准API,专门用于处理继承结构下的实体类型向下转型,针对SINGLE_TABLE继承策略不会产生额外的表连接,只会自动在生成的SQL中追加鉴别器列的判断逻辑。- 最终生成的SQL会自动过滤掉
pType='E3'的Entity3记录,不会出现访问不存在字段的错误,核心SQL逻辑大致如下:
SELECT m.* FROM moral_entity m INNER JOIN partner p ON m.fk_partner = p.internal_id WHERE (p.p_type = 'E1' AND p.category_code = 'ABC') OR (p.p_type = 'E2' AND p.category_code = 'ABC')
- 如果你需要保留partner为null的MoralEntity记录,可以把初始join改成左连接:
root.join("partner", JoinType.LEFT),但当前需求是匹配partner.category.code = "ABC",默认的内连接已经满足要求。
内容的提问来源于stack exchange,提问作者Aymen Kanzari
相关产品推荐
相关产品推荐

