对不起,如果我的术语不正确.
我们使用spring数据,JpaRepositories和条件查询作为查询数据库数据的方法.
我有一个问题,当我在下面的代码示例中结合两个规范,例如我在hasCityAndTimeZone中使用hasTimeZone和hasCity时,它会在同一个表上连接两次,所以下面的查询看起来像
select * from Staff,Location,Location
有没有办法让这两个规范使用相同的连接而不是每个定义它们自己的连接基本相同?
对不起代码可能不完整我只是想展示一个简单的例子.
class Staff {
private Integer id;
private Location location;
}
class Location {
private Integer id;
private Integer timeZone;
private Integer city;
}
class StaffSpecs {
public static Specification<Staff> hasTimeZone(Integer timeZone) {
return new Specification<Staff>() {
@Override
public Predicate toPredicate(Root<Staff> root,CriteriaQuery<?> query,CriteriaBuilder cb) {
Path<Integer> timeZonePath = root.join(Staff_.location).get(Location_.timeZone);
return cb.equal(timeZonePath,timeZone);
}
}
}
public static Specification<Staff> hasCity(Integer city) {
return new Specification<Staff>() {
@Override
public Predicate toPredicate(Root<Staff> root,CriteriaBuilder cb) {
Path<Integer> cityPath = root.join(Staff_.location).get(Location_.city);
return cb.equal(cityPath,city);
}
}
}
public static Specification<Staff> hasCityAndTimeZone(Integer city,Integer timeZone) {
return where(hasCity(city)).and(hasTimeZone(timeZone));
}
}
解决方法
不幸的是,没有开箱即用的方式. Spring Data在内部使用QueryUtils.getorCreateJoin(…)中的一些连接重用.您可以在根上找到可能已存在的连接,并在适当的地方重用它们:
private static Join<?,?> getorCreateJoin(From<?,?> from,String attribute) {
for (Join<?,?> join : from.getJoins()) {
boolean sameName = join.getAttribute().getName().equals(attribute);
if (sameName && join.getJoinType().equals(JoinType.LEFT)) {
return join;
}
}
return from.join(attribute,JoinType.LEFT);
}
请注意,这只有在我们有效地知道自己添加哪些连接时才有效.使用规格时你也应该这样做,但我只是想确保没有人认为这是所有情况下的通用解决方案.