JPA 标准搜索具有子类的抽象集合中的属性

标签 jpa inheritance collections spring-data criteria

我正在使用 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/

相关文章:

java - JPA元模型生成问题

java - 如何比较日期从java到mysql时间戳字段

IIS web.config - 多个网站的同一个文件

c++ - 当之后仍需要使用源对象时,调用父级 move 分配运算符

java - 泛型 - 集合中的 Java 集合

java - JPA ID生成策略

hibernate - JPA 相关子查询中缺少 "from"

VB.NET 继承 - 派生类中的所有属性都必须在基类中声明吗?

wpf - 当 ItemsSource 为空或 null 时,MVVM WPF 将 ListBox 替换为 Label

java - 为什么 Hashtable 内部使用 Entry<?,?>?