我正在使用Spring数据规范来编写使用JPA条件API的条件查询。
我有一个名为Thing
的班级,其Set<Characteristic>
属性。{
课程Characteristic
是一个抽象类,其中包含id
和一些共享的基本属性。
然后我有几个扩展Characteristic
并定义value
属性的具体类。
IntegerCharacteristic
value
属性为Integer
DecimalCharacteristic
value
属性为Double
StringCharacteristic
value
属性为String
BooleanCharacteristic
value
属性为Boolean
每个Thing
在Characteristic
集合中可以包含任意具体类型的0个或多个characteristics
。
在数据库中,类层次结构与连接的继承策略一起存储(5个表):
我需要使用JPA条件API 来搜索至少具有指定值的特征的所有内容。
我编写了一个SQL查询草稿,我想用JPA标准API重现:
SELECT DISTINCT thing.id
FROM thing
LEFT OUTER JOIN thing_has_characteristic has_c
ON ( has_c.thing_id = thing.id )
LEFT OUTER JOIN characteristic c
ON ( c.id = has_c.characteristic_id )
LEFT OUTER JOIN integer_characteristic integer_c
ON ( integer_c.characteristic_id = c.id )
LEFT OUTER JOIN string_characteristic string_c
ON ( string_c.characteristic_id = c.id )
LEFT OUTER JOIN boolean_characteristic boolean_c
ON ( boolean_c.characteristic_id = c.id )
LEFT OUTER JOIN decimal_characteristic decimal_c
ON ( decimal_c.characteristic_id = c.id )
WHERE integer_c.value = "9694"
OR string_c.value = "9694"
OR decimal_c.value = "9694"
OR boolean_c.value = "9694";
当试图将其转换为JPA标准时,我会陷入困境,因为我认为我需要从特征集中构建一个子查询来区分我所拥有的四种类型的特征类。
现在,我尝试了一个只有Integer和String类型的小查询,但我对如何使它与特征的子类层次结构一起工作感到困惑。
private Specification<Thing> buildSearchSpecificationByCharacteristicValue(String value) {
return (Specification<Thing>) (root, query, builder) -> {
SetJoin<Thing,IntegerCharacteristic> integers = root.<Thing,IntegerCharacteristic>joinSet("characteristics", JoinType.LEFT );
Predicate isInteger;
try{
isInteger = builder.equal(integers.get("value"), Integer.parseInt(value));
}catch(NumberFormatException e){
isInteger = builder.disjunction();
}
SetJoin<Thing,StringCharacteristic> strings = root.<Thing,StringCharacteristic>joinSet("characteristics", JoinType.LEFT);
Predicate isString = builder.equal(strings.get("value"), value);
return builder.or(
isInteger,
isString
);
};
}
它会产生以下错误:
org.springframework.dao.InvalidDataAccessApiUsageException:
Unable to locate Attribute with the the given name [value] on this
ManagedType [com.xxxxxxxx.common.domain.DomainObject];
nested exception is java.lang.IllegalArgumentException:
Unable to locate Attribute with the the given name [value]
on this ManagedType [com.xxxxxxxx.common.domain.DomainObject]
答案 0 :(得分:2)
好的,我找到了解决问题的方法:
以下是一个仅包含整数类型标准的示例,但它隐含了如何为其他类型执行此操作。
return (Specification<Thing>) (root, query, builder) -> {
Path<Characteristic> characteristics = root.join("characteristics", JoinType.LEFT);
query.distinct(true);
Subquery<IntegerCharacteristic> integerSub = query.subquery(IntegerCharacteristic.class);
Root integerRoot = integerSub.from(IntegerCharacteristic.class);
integerSub.select(integerRoot);
integerSub.where(builder.equal(integerRoot.get("value"),Integer.parseInt(value)));
return builder.in(characteristics).value(integerSub);
};