1

实体

我有一个属性为文本 [] 的实体:

    @Entity(name = "entityname")
@Table(name = "tablename")
@ToString
@TypeDefs({
  @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
  @TypeDef(name = "list-array", typeClass = ListArrayType.class)
})
public class EntityClass extends Audit
...

  @Type(type = "list-array")
  @Column(name = "participants", columnDefinition = "text[]")
  private List<String> participants;
  ....

存储库

我想用过滤器执行和 findAll。此过滤器是规范规范

data = entityRepository.findAll(filter, pageRequest);

过滤器是根据规范实现的:

public class Filter<T> implements Specification<T> {

  private final List<Condition> conditions = new ArrayList<>();

  public void addCondition(Condition condition) {
    this.conditions.add(condition);
  }

  private List<Predicate> buildPredicates(Root root, CriteriaQuery query, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();
    for (Condition condition : conditions) {
      predicates.add(buildPredicate(condition, root, query, cb));
    }
    return predicates;
  }

  public Predicate buildPredicate(
      Condition condition, Root root, CriteriaQuery query, CriteriaBuilder cb) {
    if (!condition.getType().getValue().contains(condition.getComparison())) {
      throw new RuntimeException("UNSUPPORTED_COMPARISON_FOR_SPECIFIED_TYPE");
    }
    switch (condition.getComparison()) {
      case EQ:
        if (condition.getValue().getClass().isArray()) {
          final Predicate[] predicatesList =
              Arrays.stream((Object[]) condition.getValue())
                  .map(conditionValue -> cb.equal(root.get(condition.getField()), conditionValue))
                  .toArray(Predicate[]::new);
          return cb.or(predicatesList);
        }
        return cb.equal(root.get(condition.getField()), condition.getValue());
      case GT:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.greaterThan(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.gt(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case GTE:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.greaterThanOrEqualTo(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.ge(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case LT:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.lessThan(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.lt(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case LTE:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.lessThanOrEqualTo(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.le(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case FULL_TEXT:
        return cb.isTrue(cb.function("fts", Boolean.class, cb.literal(condition.getValue())));
      case JSONB_ARRAY_IN:
        return cb.isTrue(
            cb.function(
                "jsonb_extract_path_text", Boolean.class, cb.literal(condition.getValue())));
      case JSONB_PATH_EQ:
        return cb.isTrue(
            cb.function(
                "jsonb_array_contains",
                Boolean.class,
                cb.literal(condition.getField()),
                cb.literal(condition.getValue())));
      case IN:
        List<String> dataList = Arrays.asList(condition.getValue().toString());
        return cb.in(root.get(condition.getField())).value(dataList);

      default:
        throw new RuntimeException("UNSUPPORTED_COMPARISON");
    }
  }

  public int getConditionsCount() {
    return conditions.size();
  }

  @Override
  public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
    List<Predicate> predicates = buildPredicates(root, query, cb);
    return predicates.size() > 1 ? cb.and(predicates.toArray(Predicate[]::new)) : predicates.get(0);
  }
}

我在执行 CASE IN 时遇到问题:

      case IN:
        List<String> dataList = Arrays.asList(condition.getValue().toString());
        return cb.in(root.get(condition.getField())).value(dataList);

它在它的类中产生以下错误:

public class ListArrayTypeDescriptor extends AbstractArrayTypeDescriptor<Object> {

...

    @Override
    public Object unwrap(Object value, Class type, WrapperOptions options) {
        if (value instanceof Object[]) {
            return value;
        } else if (value instanceof List) {
            return super.unwrap(((List) value).toArray(), type, options);
        } else {
            throw new UnsupportedOperationException("The provided " + value + " is not a Object[] or List!");
        }
    }
    
...

堆栈跟踪显示消息:

java.lang.UnsupportedOperationException: The provided d08d7785-1153-4bb3-b58c-6c79bf5a37f8 is not a Object[] or List!
    at com.vladmihalcea.hibernate.type.array.internal.ListArrayTypeDescriptor.unwrap(ListArrayTypeDescriptor.java:60)
    at 
  

您是否知道在我的 CASE IN 实施中这是错误的?

4

1 回答 1

1

我尝试了很多选择,直到找到解决方案:

case ANY:列表谓词 = new ArrayList<>(); 表达式分隔符 = cb.literal(",");

    predicates.add(cb.like(
        cb.function(
            "array_to_string", String.class, root.get(condition.getField()), delimiter),
        "%" + condition.getValue().toString().toLowerCase() + "%"));
  return cb.and(predicates.toArray(new Predicate[0]));

如果有人需要使用标准构建器实现“任何”,我希望有所帮助。

于 2022-02-10T14:58:01.727 回答