我刚刚开始使用Specification
和Criteria
*对象,我坚持做一个简单的左连接,并将一个值与一个连接的实体属性进行比较。
由于这个即将构建的查找/选择函数迟早会非常动态,所以我决定使用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
参数...
有没有人暗示我做错了什么?
答案 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));