简体   繁体   中英

how to transform JPA specification from child entity to parent entity

I have a rather big system with a specification that is built by several methods on a child entity. So I have a User with a OneToMany on pets, as in this question . My relation is bidirectional, so Pet also has a ManyToOne relationship on User, and I'm struggling in transforming the specification on child entity to apply on parent entity instead.

Most questions I looked up showed how to apply a specification on a different entity, OR to get a different entity once the specification was executed. This is NOT what i'm looking for.

I'm trying to write a method like this :

public static Specification<User> extendsPetSpecToUser(
          Specification<Pet> petSpec) {
// ???
  }

but I don't know how to write it (I tried using Join, but didn't manage to "say" to JPA to combine the join and the specification to query with a different root but similar constraints)

Given the specification is big AND also used in other parts to query directly for Pet, rewriting it from a different root isn't really an option.

Thank you for your time, and sorry if this is a duplicate, I really didn't see another question matching my needs.

First, it feels like this problem hides a weird construction of the queries you use.
Why would you build a Specification<Pet> if you need Specification<User> at the end ?
There might be a code architecture to think about.

Anyway, to achieve the mentioned goal, have you tried using subqueries ?

public class TransformToUser implements Specification<User> {

  private final Specification<Pet> specification;

  public TransformToUser (Specification<Pet> specification) {
    this.specification = specification;
  }

  @Override
  public Predicate toPredicate(
      Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

    Subquery<Pet> subqueryPet = criteriaQuery.subquery(Pet.class);
    Root<Pet> fromPet = subqueryDeclaration.from(Pet.class);
    subqueryPet.select(fromPet);
    subqueryPet.where(
        specification.toPredicate(fromPet, criteriaQuery, criteriaBuilder));

    return root.get(User_.pets).in(subqueryPet);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM