【问题标题】:Spring-data: Specifications & JPA criterias: how to left join and search/filter in collection propertiesSpring-data:规范和 JPA 标准:如何在集合属性中左连接和搜索/过滤
【发布时间】:2017-06-07 17:42:27
【问题描述】:

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

在我尝试执行我的第一步之前,Specifification 我有一个使用@Query 注释的存储库函数并且工作正常:

@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 名称的规范,但我仍然无法正确执行此连接以将名称参数与Alias 值属性进行比较...

第一个实体:

@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));
        }
    };
}

使用这个函数可以让我参加所有比赛,并且似乎忽略了名称参数。 打开休眠调试/跟踪日志会显示原因。生成的 sql 作为唯一的 where 条件 where 1=1.

在打开 descriptor.sql.BasicBinder 参数的日志记录时也没有显示名称值...

有人提示我做错了什么吗?

【问题讨论】:

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


    【解决方案1】:

    找到了一个稍微不同的例子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));
    

    【讨论】:

      猜你喜欢
      • 2020-11-23
      • 2017-05-12
      • 1970-01-01
      • 2020-04-20
      • 1970-01-01
      • 1970-01-01
      • 2016-02-17
      • 2019-08-26
      • 2013-09-13
      相关资源
      最近更新 更多