Java 一对多关系的JPA条件查询,子对象上的谓词不起作用

Java 一对多关系的JPA条件查询,子对象上的谓词不起作用,java,jpa,Java,Jpa,我有一个母公司 @Entity @Table(name = "tblmodule", uniqueConstraints = { @UniqueConstraint(columnNames = "name") }) @SequenceGenerator(name = ACLEntityConstant.SEQ_MODULE, initialValue = 1, allocationSize = 100) public class Module implements BaseEntity

我有一个母公司

@Entity
@Table(name = "tblmodule", uniqueConstraints = {
    @UniqueConstraint(columnNames = "name")
})
@SequenceGenerator(name = ACLEntityConstant.SEQ_MODULE, initialValue = 1, allocationSize = 100)
public class Module implements BaseEntity {

    private static final long serialVersionUID = -4924925716441434537L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ACLEntityConstant.SEQ_MODULE)
    private Long id;

    @Column
    private String name;

    @Column
    private String displayName;

    @OneToMany(mappedBy = "module")
    @JsonManagedReference
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<SubModule> subModule;

    //getters and setters
}
我正在尝试使用条件查询查找子模块的特定名称为“submodule1”的模块。这是我的密码:

    CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
    CriteriaQuery cq = cb.createQuery();
    Root root = cq.from(Module.class);
    cq.select(root);
    ListJoin join = root.joinList("subModule");
    cq.where(cb.equal(join.get("name"), "submodule1"));
    cq.distinct(true);
    cq.groupBy(root.get("name"));
    TypedQuery query = getEntityManager().createQuery(cq);
    return query.getResultList();
使用这段代码,它给出了模块中的所有子模块

有没有办法只选择名为“submodule1”的子模块?
谢谢

您可以返回包含名称为somevalue的子模块的所有模块,但是,在JPA中,不可能获得包含由原始查询中的某些内容过滤的子模块列表的“模块”实例-JPA需要返回反映数据库中状态的托管模块实例,以便它可以管理您可能进行的任何更改

不要使用对象中设置的module.submodules,而是直接使用类似于从子模块子模块中选择子模块的查询来查询子模块,其中submodule.name=:name。然后,可以使用结果基于submodule.module创建子模块集合的映射

表A

表B

使用其标准生成器时: 从a,b中选择a.*,b.*,其中a.a_id=b.b_id,a.name='X'和b.salary=2000

通过上面的查询,我们应该得到字段:salary=2000

但在JPA中,对于@OneToMany关系,查询首先在主记录上启动,使用所有条件并只获取主记录。 稍后会单独触发查询,但B表条件不会包含所有条件,而是只包含一个条件,即仅使用一个条件B.A_id=[primarykeyfetched from master]获取主记录的主键值

从表B中选择B.*连接表A,其中B.A_id=表示单个id

这就是后端发生的情况,因此它会获取所有与A_id匹配的B记录,而不管薪资是否匹配

A.A_id  A.name  A.age   B.B_id  B.salary    B.dept
1        X      34       11     2000        IT
1        X      34       22     3000        IT
解决方案很简单:创建一个独立的类,其中需要@OneToMany relationship的字段

第一步

步骤2


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

我认为根据上述标准,您只会得到至少有一个子模块名为submodule1的模块。但在返回的子模块列表中,您不需要所有子模块,而是只需要与子模块1匹配的子模块作为名称?是吗?是的,绝对正确。我怀疑这是否真的可能。我记得读过一些关于它的文章。我会发布我发现的链接。为什么不看看生成的SQL?可能是重复的
A_IdPKey)   name    age

1            X       34
B_id(PK)    A_id(FrnKey)    salary  
11             1             2000   
22             1             3000   
A.A_id  A.name  A.age   B.B_id  B.salary    
1          X    34       11     2000
A.A_id  A.name  A.age   B.B_id  B.salary    B.dept
1        X      34       11     2000        IT
1        X      34       22     3000        IT
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;
    }

    getters...

    setters....

}
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());
}