假设我有以下课程:(简化为极端)
@Entity
@Table(name = "USER")
public class User {
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private BillingAddress billingAddress;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private ShippingAddress shippingAddress; // This one CAN be null
}
并且*Address
都继承了这个摘要:(再次,它是额外简化的)
public abstract class Address {
@OneToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "USER_ID")
private User user;
@NotEmpty
@Size(max = 32)
@Column(name = "ADDR_TOWN")
private String town;
}
我尝试了JPA规范,正如Spring的博客文章所解释的那样:
/**
* User specifications.
*
* @see <a href="https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl">Advanced Spring Data JPA - Specifications and Querydsl</a>
*/
public class UserSpecifications {
public static Specification<User> likeTown(String town) {
return new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.get("billingAddress").get("town")), '%' + StringUtils.lowerCase(town) + '%');
}
};
}
使用此&#34;规范&#34;如下:
List<User> users = userRepository.findAll(UserSpecifications.likeTown(myTown));
但是现在,我还想在城镇搜索可能不存在的shippingAddress。
我尝试在cb.like
中合并cb.or
,但结果是SQL查询对shippingAddress有一个INNER JOIN,这是不正确的,因为如上所述,它可能为null,所以我&#39 ; d喜欢LEFT JOIN。
怎么做?
感谢。
答案 0 :(得分:3)
指定联接类型:
town = '%' + StringUtils.lowerCase(town) + '%';
return cb.or(
cb.like(cb.lower(root.join("billingAddress", JoinType.LEFT).get("town")), town),
cb.like(cb.lower(root.join("shippingAddress", JoinType.LEFT).get("town")), town));
答案 1 :(得分:0)
不知道是否有帮助。
我遇到了同样的问题。我能解决它的唯一方法是使用子查询。
例如,这类似于:
JPASubQuery subquery = new JPASubQuery();
subquery = subquery .from( /* tableB */);
subquery .where(/* conditions */);
然后使用我将子查询添加到谓词:
predicate.and(subquery.exists());
注意:在我的情况下,它有助于我广泛使用规范。在大多数情况下,性能影响似乎并不那么好。
编辑:
我刚才意识到前一个例子只适用于我的情况,因为我正在使用query-dsl
。
在您的情况下,请查看JPA 2.0, Criteria API, Subqueries, In Expressions以创建子查询并将其加入谓词条件。