使用GROUPBY和having子句的JPA标准Api
我有一个实体,比如说设备,它有一个MAP类型的元素集合使用GROUPBY和having子句的JPA标准Api,jpa,jpa-2.0,criteria-api,Jpa,Jpa 2.0,Criteria Api,我有一个实体,比如说设备,它有一个MAP类型的元素集合 class Device{ BigDecimal id; @ElementCollection MAP<String, String> properties; ...... } 经过两周的努力,我终于让它开始工作了。解决方案很简单,但在阅读了这里的JPA规范之后,终于想到了它 问题是groupBy中的column名称也应该在select子句中传递。在我的例子中,应该提到的是,即使设备是设备类的成员,JPA criteria
class Device{
BigDecimal id;
@ElementCollection
MAP<String, String> properties;
......
}
经过两周的努力,我终于让它开始工作了。解决方案很简单,但在阅读了这里的JPA规范之后,终于想到了它
问题是groupBy中的column名称也应该在select子句中传递。在我的例子中,应该提到的是,即使设备是设备类的成员,JPA criteria API也不会从设备中获取该ID。如果您的JPA提供商在组中丢失了该ID,请向其提出错误。也许可以尝试在groupBy/have?之前设置where,即使在将where子句语句移到groupBy之上并具有相同的问题之后,也可以尝试设置where。假设这是EclipseLink(基于生成的SQL,但您仍然没有说使用了哪一个),所以请查看将其升级到最新版本或报告一个错误。
{
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Device> deviceQuery = criteriaBuilder.createQuery(Device.class);
Root<Device> device = deviceQuery.from(Device.class);
deviceQuery.select(device);
List<Predicate> criteria = new ArrayList<Predicate>();
if(!properties.isEmpty()){
MapJoin<Device, String, String > propertyJoin =device.joinMap("deviceProperties",JoinType.INNER);
Expression<BigDecimal> id = device.get(LocationConstants.ID);
for(Map.Entry<String,String> property : properties.entrySet()){
String key = property.getKey();
String value = property.getValue();
criteria.add(criteriaBuilder.and(criteriaBuilder.equal(propertyJoin.key(), key),
criteriaBuilder.equal(propertyJoin.value(), value)));
}
deviceQuery.groupBy(id);
deviceQuery.having(criteriaBuilder.equal(criteriaBuilder.count(id), properties.size()));
}
deviceQuery.where(criteriaBuilder.or(criteria.toArray(new Predicate[0])));
}
SELECT t1.ID, t1.DEVICE_TYPE, t1.CREATEDBY, t1.CREATEDON, t1.DESCRIPTION, t1.MODIFIEDBY, t1.MODIFIEDON, t1.NAME, t1.ID1, t1.ID2, t1.ID3, t1.STATUS, t1.INSTANCE, t1.NAMESPACE, t1.URL, t1.MAJOR, t1.MINOR, t1."UID"
FROM LOC_DEVICE_PROPERTY t0, LOC_DEVICE t1
WHERE ((((((t0.PROPERTY_KEY = ?) AND (t0.PROPERTY_VALUE = ?))
OR ((t0.PROPERTY_KEY = ?) AND (t0.PROPERTY_VALUE = ?)))
OR ((t0.PROPERTY_KEY = ?) AND (t0.PROPERTY_VALUE = ?)))
OR ((t0.PROPERTY_KEY = ?) AND (t0.PROPERTY_VALUE = ?)))
AND (t0.Device_ID = t1.ID))
ORDER BY t1.ID ASC
[[bind => [8 parameters bound]]]