[英]Left Join in Spring Data JPA's Specification
Assume I'm having the following class: (simplified to the extreme)假设我有以下课程:(简化到极致)
@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
}
and both *Address
inherit from this abstract: (again, it's extra-simplified)并且两个
*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;
}
I tried the JPA Specifications, as explained by Spring's blog post:我尝试了 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) + '%');
}
};
}
Using this "specification" as follow:使用这个“规范”如下:
List<User> users = userRepository.findAll(UserSpecifications.likeTown(myTown));
But now, I also want to search the town for the shippingAddress, which might not exist.但是现在,我还想在城镇中搜索可能不存在的shippingAddress。 I tried combining both
cb.like
in a cb.or
but it turned out the resulting SQL query had an INNER JOIN for the shippingAddress, which is incorrect because, as said above, it might be null, so I'd like a LEFT JOIN.我尝试将
cb.like
与cb.or
结合使用,但结果是结果 SQL 查询对 shippingAddress 有一个 INNER JOIN,这是不正确的,因为如上所述,它可能为空,所以我想要一个 LEFT JOIN .
How to do that?怎么做?
Thanks.谢谢。
Specify join type:指定连接类型:
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));
Don't know if it helps.不知道有没有帮助。
I had the same problem.我有同样的问题。 The only way I could solve it was to use a subquery.
我可以解决它的唯一方法是使用子查询。
For instance this would resemble something like that :例如,这将类似于以下内容:
JPASubQuery subquery = new JPASubQuery();
subquery = subquery .from( /* tableB */);
subquery .where(/* conditions */);
Then use i add the subquery to the predicate :然后使用我将子查询添加到谓词:
predicate.and(subquery.exists());
NB : In my case it helped as i am extensively using Specifications.注意:就我而言,它有帮助,因为我广泛使用规范。 In most cases, the performance impact didn't seem that great.
在大多数情况下,性能影响似乎并不大。
EDIT : I just realized that the former example worked only in my case as i'm using query-dsl
.编辑:我刚刚意识到前一个例子只适用于我的情况,因为我使用的是
query-dsl
。
In your case, have a look at JPA 2.0, Criteria API, Subqueries, In Expressions to create a subquery and join it to your predicate conditions.在您的情况下,请查看JPA 2.0、Criteria API、Subqueries、In Expressions以创建子查询并将其加入您的谓词条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.