【问题标题】:Left Join in Spring Data JPA's SpecificationSpring Data JPA 规范中的左连接
【发布时间】:2017-05-12 23:17:24
【问题描述】:

假设我有以下课程:(简化到极致)

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

但现在,我还想在城镇中搜索可能不存在的 shippingAddress。 我尝试在cb.or 中结合cb.like,但结果是生成的SQL 查询有一个用于shippingAddress 的INNER JOIN,这是不正确的,因为如上所述,它可能为null,所以我想要一个LEFT JOIN .

怎么做?

谢谢。

【问题讨论】:

    标签: java spring-data-jpa spring-data jpa-2.0 specifications


    【解决方案1】:

    指定连接类型:

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

    【讨论】:

      【解决方案2】:

      不知道有没有用。

      我遇到了同样的问题。我可以解决它的唯一方法是使用子查询。

      例如,这将类似于:

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

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

      predicate.and(subquery.exists());
      

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

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

      在您的情况下,请查看 JPA 2.0, Criteria API, Subqueries, In Expressions 以创建子查询并将其加入您的谓词条件。

      【讨论】:

        猜你喜欢
        • 2016-07-22
        • 2015-06-03
        • 1970-01-01
        • 2020-10-10
        • 1970-01-01
        • 2016-01-06
        • 2016-02-17
        • 2017-01-12
        • 2019-05-25
        相关资源
        最近更新 更多