我正在使用 Spring 数据规范来使用 JPA 标准 API 编写标准查询。
我有一个名为 Thing
的类(class)其中有 Set<Characteristic>
属性。
类(class)Characteristic
是一个抽象类,其具有 id
以及一些共同的基本属性。
然后我有几个扩展 Characteristic
的具体类并定义 value
属性。
-
IntegerCharacteristic
其中value
属性是Integer
-
DecimalCharacteristic
其中value
属性是Double
-
StringCharacteristic
其中value
属性是String
-
BooleanCharacteristic
其中value
属性是Boolean
每个Thing
可以有 0 个或多个 Characteristic
他的任何具体类型 characteristics
设置。
在数据库中,类层次结构使用连接的继承策略存储,如下(5 个表):
- 特征(id + 一些公共(public)字段)
- integer_characteristic(外键 + INT 值)
- decimal_characteristic(外键 + DECIMAL 值)
- string_characteristic(外键 + VARCHAR 值)
- boolean_characteristic(外键 + TINYINT 值)
我需要使用 JPA criteria 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 标准时,我陷入了困境,因为我认为我需要从特征集中构建一个子查询来区分我拥有的四种类型的特征类。
现在,我尝试了一个仅包含整数和字符串类型的小查询,但我对如何使其与特征的子类层次结构一起使用感到困惑。
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]
最佳答案
好的,我已经找到了问题的解决方案:
这是一个仅包含整数类型标准的示例,但隐含了如何针对其他类型执行此操作。
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);
};
关于JPA 标准搜索具有子类的抽象集合中的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36199001/