Spring Data JPA规范中的Left Join

问题描述 投票:0回答:3

假设我正在上以下课程:(简化到极致)

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

使用此“规范”如下:

List<User> users = userRepository.findAll(UserSpecifications.likeTown(myTown));

但是现在,我还想在城镇中搜索送货地址,该地址可能不存在。 我尝试将两个

cb.like
组合在
cb.or
中,但结果发现生成的 SQL 查询对shippingAddress 有一个 INNER JOIN,这是不正确的,因为如上所述,它可能为 null,所以我想要一个 LEFT JOIN .

如何做到这一点?

谢谢。

java spring-data-jpa spring-data jpa-2.0 specifications
3个回答
16
投票

指定连接类型:

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
投票

不知道有没有帮助。

我也有同样的问题。我解决这个问题的唯一方法是使用子查询。

例如,这类似于:

JPASubQuery subquery = new JPASubQuery(); 
subquery = subquery .from( /* tableB */);
subquery .where(/* conditions */);

然后使用 i 将子查询添加到谓词中:

predicate.and(subquery.exists());

注意:就我而言,它很有帮助,因为我广泛使用规范。在大多数情况下,性能影响似乎并没有那么大。

编辑: 我刚刚意识到前一个示例仅适用于我的情况,因为我正在使用

query-dsl

对于您的情况,请查看 JPA 2.0、Criteria API、子查询、表达式中,以创建子查询并将其连接到您的谓词条件。


0
投票

我理解sql错误,但问题是如果使用findAll的查询没有返回所有记录,使用count的查询会自动执行,我不知道如何管理其内容是否正确

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.