我有一个父实体
@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
}
模块与SubModule有一对多关系,实体类如下
@Entity
@Table(name = "tblsubmodule", uniqueConstraints = {
@UniqueConstraint(columnNames = {"id", "name"})
})
@SequenceGenerator(name = ACLEntityConstant.SEQ_SUBMODULE, initialValue = 1, allocationSize = 100)
public class SubModule implements BaseEntity {
private static final long serialVersionUID = 5452251016263080356L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ACLEntityConstant.SEQ_SUBMODULE)
private Long id;
@Column
private String name;
@Column
private String displayName;
@ManyToOne
@JsonBackReference
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Module module;
}
我正在尝试使用条件查询找到具有特定名称(&#39; submodule1&#39;)的子模块的模块。这是我的代码:
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();
使用此代码,它为我提供了模块中的所有子模块。
有没有办法只选择名称为子模块的子模块&#39;? 谢谢
答案 0 :(得分:2)
您可以返回包含名称= somevalue的子模块的所有模块,但在JPA中无法获取&#39; module&#39;具有由原始查询中的某些内容过滤的子模块列表的实例 - JPA需要返回反映数据库中状态的托管模块实例,以便它可以管理您可能进行的任何更改。
而不是使用对象中设置的module.submodules,直接使用类似于"Select submodule from SubModule submodule where submodule.name = :name"
的查询查询子模块。然后,您可以使用结果基于submodule.module创建子模块集合的映射。
答案 1 :(得分:2)
表A
A_IdPKey) name age
1 X 34
表B
B_id(PK) A_id(FrnKey) salary
11 1 2000
22 1 3000
使用其Criteria构建器时:
select a.*,b.* from A a, B b where a.A_id=b.B_id and a.name='X' and b.salary=2000
通过上述查询,我们应该得到字段:salary=2000
A.A_id A.name A.age B.B_id B.salary
1 X 34 11 2000
但在JPA中,对于@OneToMany
关系,Query首先在master上触发,所有Criteria和fetches只是主记录。
稍后单独触发查询,但B表标准将不包含所有条件,而是仅包含一个条件,即仅使用一个条件b.A_id=[primarykeyfetched from master]
select B.* from Table B join Table A where B.A_id=(for individual Ids)
这就是Backend中发生的事情,因此无论薪水不匹配,它都会获取所有B
匹配A_id
的{{1}}条记录。我们正在获取
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
关系字段。
第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;
}
getters...
setters....
}
第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
的主键而不是外键。