弹簧数据:规格& JPA标准:如何在集合属性中保持连接和搜索/过滤

时间:2017-06-07 17:42:27

标签: hibernate spring-data spring-data-jpa

我刚刚开始使用SpecificationCriteria *对象,我坚持做一个简单的左连接,并将一个值与一个连接的实体属性进行比较。 由于这个即将构建的查找/选择函数迟早会非常动态,所以我决定使用Criteria对象而不是使用不同的参数构建不同的函数。 我的真实实体有一些更多的属性,但我把它分解为简化它。

在我尝试完成我的第一步之前,Specifification我有一个用@Query注释的Repository函数,并且工作正常:

@Query( "SELECT DISTINCT c FROM Competition c " +
    "LEFT JOIN c.aliases a " +
    "WHERE " +
    "(lower(a.value) = :name OR lower(c.name) = :lowerCaseName) " +
    "... and so on ")

后来我尝试构建一个忽略小写和Competition名称的规范,并且我仍然无法如何进行连接,以便将name参数与Alias value属性进行比较...

第一个实体:

@Entity
public class Competition extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @ManyToMany(cascade = CascadeType.MERGE)  
    @JoinTable(name="competition_name_alias", joinColumns=@JoinColumn(name="competition_id"), inverseJoinColumns=@JoinColumn(name="alias_id"))  
    private Set<Alias> aliases = new HashSet<>();

    ...
}

第二实体:

@Entity
public class Alias extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String value;

    ...
}

规格:

public static Specification<Competition> withLowerCaseName(String name) {
    return new Specification<Competition>() {
        @Override
        public Predicate toPredicate(Root<Competition> product, CriteriaQuery<?> query, CriteriaBuilder builder) {
            final List<Predicate> predicates = new ArrayList<Predicate>();

            Root<Competition> root = query.from(Competition.class);

            Subquery<Alias> subquery = query.subquery(Alias.class);
            SetJoin<Competition, Alias> aliases = root.join(Competition_.aliases);

            Predicate predicate = builder.equal(aliases.get(Alias_.value), name);
            builder.and(predicate);

            Predicate[] predicatesArray = new Predicate[predicates.size()];

            query.distinct(true);

            return builder.and(predicates.toArray(predicatesArray));
        }
    };
}

使用此功能可以获得所有比赛并且似乎忽略了name参数。 打开hibernate调试/跟踪日志记录会显示原因。生成的sql具有唯一的where条件 where 1=1

在打开descriptor.sql.BasicBinder参数...

的日志记录时,也没有显示名称值

有没有人暗示我做错了什么?

1 个答案:

答案 0 :(得分:0)

找到了一个略有不同的例子here并为我的星座改变了它。似乎工作......

final Subquery<Alias> aliasSubquery = query.subquery(Alias.class);
final Root<Alias> alias = aliasSubquery.from(Alias.class);
final Expression<Set<Alias>> aliases = product.get(Competition_.aliases);
aliasSubquery.select(alias);
aliasSubquery.where(builder.equal(builder.lower(alias.get(Alias.value)), lowerCaseName), builder.isMember(alias, aliases));

builder.and(builder.exists(aliasSubquery));