如何使用Criteria Query查询关联继承链中的多实体属性?
跨JPA继承实体的Criteria Query实现
要实现跨Anuncio、Produto、Bovino三个实体的属性查询,核心是处理JPA的JOINED继承关系,通过treat操作访问子类属性,同时关联主实体与父类实体。以下是修正后的实现方案:
关键步骤说明
- 关联主实体与父类:从
Anuncio根对象关联到Produto实体,使用INNER JOIN确保只返回关联了有效Produto的Anuncio。 - 特化父类为子类:通过
CriteriaBuilder.treat()将Produto的关联对象转换为Bovino类型,这样就能直接访问Bovino的专属属性。 - 添加类型过滤:必须添加Produto类型为Bovino的条件,避免因其他子类不存在目标属性导致的查询错误。
完整代码实现
public List<Anuncio> getFilteredBuilder(Integer qualidadeGado, Integer racaGado, Integer idadeStart, Integer idadeEnd){ CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Anuncio> cq = cb.createQuery(Anuncio.class); Root<Anuncio> rootAn = cq.from(Anuncio.class); // 关联Anuncio到Produto(一对一关联,用INNER JOIN) Join<Anuncio, Produto> produtoJoin = rootAn.join("produto", JoinType.INNER); // 将Produto特化为Bovino子类,允许访问子类属性 Join<Anuncio, Bovino> bovinoJoin = cb.treat(produtoJoin, Bovino.class); List<Predicate> preds = new ArrayList<>(); // 添加类型过滤:确保Produto是Bovino类型 preds.add(cb.equal(produtoJoin.type(), cb.literal(Bovino.class))); // 针对Bovino的属性构建查询条件 if (qualidadeGado != null) { preds.add(cb.equal(bovinoJoin.get("qualidade"), qualidadeGado)); } if (racaGado != null) { preds.add(cb.equal(bovinoJoin.get("raca"), racaGado)); } if (idadeStart != null ) { preds.add(cb.ge(bovinoJoin.get("idadeOuMedia"), idadeStart)); } if (idadeEnd != null) { preds.add(cb.le(bovinoJoin.get("idadeOuMedia"), idadeEnd)); } cq.where(preds.toArray(new Predicate[0])); return em.createQuery(cq).getResultList(); }
注意事项
- 如果需要同时支持多个Produto子类的查询,可以通过
cb.or()组合不同子类的类型判断与对应属性条件。 - 确保实体类中Bovino确实存在
qualidade、raca、idadeOuMedia这些属性,否则需要调整get()方法中的属性名。
内容的提问来源于stack exchange,提问作者Fabrício Gustavo
相关产品推荐
相关产品推荐

