【问题标题】:JPA criteria search property in abstract collection with subclasses带有子类的抽象集合中的 JPA 标准搜索属性
【发布时间】:2016-03-24 11:24:11
【问题描述】:

我正在使用 Spring 数据规范来编写使用 JPA 条件 API 的条件查询。

我有一个名为Thing 的类,它有一个Set<Characteristic> 属性。
Characteristic 类是一个abstract 类,它有一个id 和一些共享的基本属性。

然后我有几个扩展Characteristic 并定义value 属性的具体类。

  • IntegerCharacteristic 其中value 属性是Integer
  • DecimalCharacteristic 其中value 属性是Double
  • StringCharacteristic 其中value 属性是String
  • BooleanCharacteristic 其中value 属性是Boolean

每个Thing 在他的characteristics 集合中可以有0 个或多个Characteristic 的任何具体类型。

在数据库中,类层次结构是使用联合继承策略存储的(5 个表):

  • 特征(id + 一些常用字段)
  • integer_characteristic(外键 + INT 值)
  • decimal_characteristic(外键 + DECIMAL 值)
  • string_characteristic(外键 + VARCHAR 值)
  • boolean_characteristic(外键 + TINYINT 值)

我需要使用 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 标准时,我遇到了困难,因为我认为我需要从一组 Characteristic 中构建一个子查询,以区分我拥有的四种 Characteristic 类。

现在,我尝试了一个只有 Integer 和 String 类型的小查询,但我对如何使其与 Characteristic 的子类层次结构一起工作感到困惑。

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]

【问题讨论】:

    标签: jpa inheritance collections spring-data criteria


    【解决方案1】:

    好的,我找到了解决问题的方法:

    这是一个示例,其中仅包含整数类型的标准,但隐含了如何为其他类型执行此操作。

    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);
    
    };
    

    【讨论】:

    • 您是否考虑过在这种情况下使用 jpql,我认为它会容易得多。
    • select distinct o.id from thing o left join o.thing_has_characteristic has_c left join has_c.integer_characteristic integer_c left join has_c.string_characteristic string_c left join has_c.boolean_characteristic boolean_c left join has_c.decimal_characteristic decimal_c where integer_c.value = "9694" or string_c.value = "9694" or decimal_c.value = "9694"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 2013-09-13
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多