在一对多关系中指定子表的条件

时间:2014-01-09 20:08:31

标签: java hibernate jpa one-to-many

我有两个具有一对多关系的实体对象(A和B)。我正在使用JPA(Hibernate)来连接这些表并查询它们以获取特定的结果集,但是在获取结果时我没有应用为子表(B)指定的条件。这就是我定义查询的方式:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<A> query = builder.createQuery(A.class);
Root<A> a = query.from(A.class);
Join<A, B> abJoined = a.join(A_.b);

query.distinct(true)
    .where(builder.and(
        builder.equal(a.get(A_.id), id),
        builder.equal(a.get(A_.active), 1),
        builder.equal(a.get(A_.location), 1011),
        builder.equal(a.get(A_.status), "Pending"),

        builder.equal(abJoined.get(B_.status), "Not Moved"),
        builder.greaterThan(abJoined.get(B_.detailId), 0)
    ));

当我致电entityManager.createQuery(query).getResultList();时,我得到一个实体'A'的实例,但是当我尝试通过'A'a.getB()访问'B'时,我为{{1}指定了两个标准没有应用,我得到'B'加入'A'的所有实例。为了达到这些标准,我还需要做些什么吗?如果无法应用标准,是否有推荐的方法从结果集中删除“B”的相应实例?

如有必要,我可以提供更多代码或其他详细信息。

2 个答案:

答案 0 :(得分:0)

该查询用于选择查询必须返回哪些A实体。但是A实体永远不会是仅包含其Bs子集的部分实体。它们将始终是A的完整实例,反映A在数据库中的状态,以及A与哪个B相关。

顺便说一下,即使这是可能的(它不是,并且明显禁止JPA规范),你的查询至少也必须使用获取连接来加载Bs。否则,查询只返回A的状态,并且链接的Bs被懒惰地加载。

答案 1 :(得分:0)

但在JPA中,对于@OneToMany关系,Query首先在master上触发,所有Criteria和fetches只是主记录。 稍后单独地查询被触发,但是但是...... B表标准将不包含所有条件,而是仅包含一个条件,即仅获取主记录的主键VALUE,即只有一个条件“b。 A_id = [主要从主人那里获取]“

解决方案很简单 创建一个独立的类,我们需要@OneToMany关系字段

第1步

public class AB {

    private A a;
    private B b;  //@OneToMany with A in the Entity class definitions

public AB(){}

public AB(A a, B b){ ///Very Important to have this constructor
    this.a=a;
    this.b=b;
}

getter setter....

}

第2步

CriteriaQuery<AB> q = criteriaBuilder.createQuery(AB.class);
Root<A> fromA = criteriaQuery.from(A.class);      
List<Predicate> predicates = new ArrayList<Predicate>();         
Join<A,B> fromB = fromA.join("b", JoinType.INNER);/*"b",fieldName of B in entity Class A*/
criteriaQuery.select(criteriaBuilder.construct(AB.class,A,B));//looks AB's 2 param constr.
predicates.add(criteriaBuilder.equal(fromA.get("name"), filter.getName()));   
predicates.add(criteriaBuilder.equal(fromB.get("salary"), filter.getSalary()));
.......... 
List<AB> ABDataList = typedQuery.getResultList();  
for(AB eachABData :ABDataList){
    ....put in ur objects
    obj.setXXX(eachABData.getA().getXXX());
    obj.setYYY(eachABData.getB().getYYY());
} 

这将给出应用所有条件的所有结果到主表A,并比较表B的主键而不是外键。