Можно ли повторно использовать спецификации в другом объекте в Spring Data Jpa? - PullRequest
2 голосов
/ 29 января 2020

Учитывая эти сущности:

public class Parent {
    private List<Child> children;

    // others fields
}

public class Child {
    private Parent parent;

    // others fields
}

Я хочу применить спецификацию, которая существует для Parent, но с Child как root:

public class ParentSpecs {
    public static Specification<Parent> withComplexFilter(String filter) {
        return (parent, query, criteriaBuilder) -> {
            Predicate predicate;
            // complex algorithm that works, but that I don't want to duplicate
            return predicate;
        };
    }
}

public class ChildSpecs {
    public static Specification<Child> withComplexFilterOnParentField(String filter) {
        return (child, query, criteriaBuilder) -> {
            Path<Object> parent = child.get("parent");
            Root<Parent> root = null; // how to build a root from the "Child" root ?
            return ParentSpecs.withComplexFilter(filter).toPredicate(root, query, criteriaBuilder);
        };
    }
}

Превращение спецификации в предикат для ее использования в ChildSpecs представляется хорошим решением?

Как мы можем использовать Root<Parent>, когда мы должны использовать Root<Child>?

1 Ответ

0 голосов
/ 29 января 2020

Тип Root в основном относится к части FROM запроса SQL. Чтобы получить еще один root, вам нужен подзапрос:

return (child, query, criteriaBuilder) -> {
  final Subquery<ReturnType> subquery = query.subquery(ReturnType.class);
  final Root<Parent> subroot = subquery.from(Parent.class);
  subquery.select("parentField");
  // call shared code
  return criteriaBuilder.equal(subquery, child.get("something"));
}

По сути это похоже на следующее SQL:

SELECT ... FROM child c WHERE c.something = (
  SELECT parentField FROM parent WHERE (...shared conditions...)
);
...