集合的Spring数据规范包含操作

时间:2017-12-08 12:34:37

标签: java spring-data spring-data-jpa hibernate-criteria criteria-api

我有两个实体AB。它们之间存在多对多关系,其中A包含B列表。 如何编写规范以检索包含具有特定名称的A的所有B个参与者?示例:

@Service
public class YourService {

    @Resource
    private ARepository repository;

    // I know how to do this type of queries with specifications
    public List<A> getByB(B b) {
        return repository.findAll(Specifications.containsB(b));
    }

    //Question: how to write Specification for this type of query?
    public List<A> getByNameOfB(String name) {
         return repository.findAll(Specifications.containsBWithName(name));
    }
} 

实体:

@Entity
public class B {

        @Id
        @SequenceGenerator(sequenceName = "B_SEQ", name = "BSeq", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BSeq")
        private Long id;

        @Column(unique = true, updatable = false)
        private String name;
}

@Entity
public class A {

    @Id
    @SequenceGenerator(sequenceName = "A_SEQ", name = "ASeq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ASeq")
    private Long id;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "A_B",
            joinColumns = {@JoinColumn(name = "A_ID", nullable = false, updatable = false)},
            inverseJoinColumns = {@JoinColumn(name = "B_ID", nullable = false, updatable = false)})
    @Fetch(value = FetchMode.SUBSELECT)
    private List<B> bList;
}

元模型:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(A.class)
public class A_ {
    public static volatile ListAttribute<A, B> bList;
}


@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(B.class)
public class B_ {
    public static volatile SingularAttribute<B, String> name;
}

检索:

public interface ARepository extends JpaRepository<A, Long>, JpaSpecificationExecutor<A> {
}

public class Specifications {

    public static Specification<A> containsB(B b) {
        return (root, query, cb) -> {
            Expression<List<B>> bList = root.get(A_.bList);
            return cb.isMember(b, bList);
        };
    }

    // HERE IS A QUESTION:

    public static Specification<A> containsBWithName(String name) {
        return (root, query, cb) -> {
            ListJoin<List<B>> bList = root.join(A_.bList);
            Expression<String> exp = bList.get(B_.name)
            //TODO how to check that name is one of the retrieved names?
            //PROBLEM, method below expects Expression<List<String>> instead of Expression<String>
            cb.isMember(name, exp); 
        };
    }
}

2 个答案:

答案 0 :(得分:7)

尝试下一步:

public static Specification<A> containsBWithName(String name) {
    return (root, query, cb) -> {
        root.join("bList", JoinType.INNER);
        return cb.equal(root.get("bList").get("name"), name);
    };
}

希望它能解决问题。

Spring数据版 1.11.4

答案 1 :(得分:2)

花了一些时间才弄清楚为什么接受的答案对我没用。 我不得不这样做:

public static Specification<A> containsBWithName(String name) {
    return (root, query, cb) -> {
        Join<Object, Object> bListJoin = root.join("bList", JoinType.INNER);
        return cb.equal(bListJoin.get("name"), name);
    };
}

Spring Data 1.11.9