JPA2 Criteria-API: select… in (select from where)

前端 未结 4 725
醉酒成梦
醉酒成梦 2020-12-18 15:22

I have the following database model:

A
aId

AB
aId
bId

B
bId
status

In a Spring data Specification, I want to return the instances of A wh

相关标签:
4条回答
  • 2020-12-18 15:43

    Select In - is an option but you could achieve same result with double join. And its easier to make such a jpa specification:
    SELECT A.ID FROM A LEFT JOIN AB ON A.ID = AB.A_ID LEFT JOIN B ON AB.B_ID = B.ID WHERE B.STATUS = 'STATUS'
    Method would look like this:

    public static Specification<A> findB(String input) {
        return new Specification<A>() {
            @Override
            public Predicate toPredicate(Root<A> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                Join<A,AB> AjoinAB = root.joinList(A_.AB_LIST,JoinType.LEFT);
                Join<AB,B> ABjoinB = AjoinAB.join(AB_.B,JoinType.LEFT);
                return cb.equal(ABjoinB.get(B_.NAME),input);
            }
        };
    }
    

    Or shorter

    public static Specification<A> findB(String input) {
        return (Specification<A>) (root, cq, cb) -> {
            Join<A,AB> AjoinAB = root.joinList(A_.AB_LIST,JoinType.LEFT);
            Join<AB,B> ABjoinB = AjoinAB.join(AB_.B,JoinType.LEFT);
            return cb.equal(ABjoinB.get(B_.NAME),input);
        };
    }
    

    I know it's been a long time since this question arose, but I came across it when I tried to do the same. This is my solution that works and I hope it helps someone.

    Entities below

    @Entity
    public class A {
        @Id
        private Long id;
        private String name;
        @OneToMany(mappedBy = "a")
        private List<AB> abList;
    }
    @Entity
    public class B {
        @Id
        private Long id;
        private String status;
        @OneToMany(mappedBy = "b")
        private List<AB> abList;
    }
    @Entity
    public class AB {
        @Id
        private Long id;
        private String name;
        @ManyToOne
        @JoinColumn(name = "a_id")
        private A a;
        @ManyToOne
        @JoinColumn(name = "b_id")
        private B b;
    }
    
    0 讨论(0)
  • 2020-12-18 15:51

    There are some good examples included on a previous post that address exactly what you're trying to accomplish here: jpa-2-0-criteria-api-subqueries-in-expressions.

    0 讨论(0)
  • 2020-12-18 15:55

    The Specification that returns instances of A using Criteria API is the following:

    public class ASpecifications {
         public static Specification<A> test(final String status) {
              return new Specification<Party>() {
              @Override
              public Predicate toPredicate(Root<A> a, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Subquery<A> sq = query.subquery(A.class);
                Root<AB> ab = sq.from(AB.class);
                sq.select(ab.get(AB_.id).get(ABPK_.a));
                sq.where(cb.equal(ab.get(AB_.id).get(ABPK_.b).get(B_.status), status));
    
                Predicate p = cb.in(a).value(sq);
                return cb.and(p);
              }
            };
         }
    }
    
    0 讨论(0)
  • 2020-12-18 15:59

    I suppose you wanted to select "A entities from AB entities where B is of provided status":

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<A> cq = cb.createQuery(A.class);
    Root<AB> ab = cq.from(AB.class);
    cq.select(ab.get("id").get("a"));
    cq.where(cb.equal(ab.get("id").get("b.status"), status));
    
    0 讨论(0)
提交回复
热议问题