2016-12-28 7 views
1

Предположим, у меня следующий класс: (упрощена до крайности)Соединение слева в спецификации Spring Data JPA в

@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, как пояснил в блоге Спринга:

/** 
* 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.like в cb.or, но получилось, что в результате SQL-запроса был INNER JOIN для shippingAddress, что неверно, потому что, как сказано выше, оно может быть нулевым, поэтому мне нужно LEFT JOIN.

Как это сделать?

Спасибо.

ответ

0

Не знаю, помогает ли это.

У меня была та же проблема. Единственный способ решить эту проблему - использовать подзапрос.

Например, это будет походить на что-то вроде этого:

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

Затем использовать я добавить подзапроса предиката:

predicate.and(subquery.exists()); 

NB: В моем случае это помогло, как я широко использовать Характеристики , В большинстве случаев влияние производительности не показалось мне таким замечательным.

EDIT: Я просто понял, что бывший пример работал только в моем случае, как я использую query-dsl.

В вашем случае просмотрите JPA 2.0, Criteria API, Subqueries, In Expressions, чтобы создать подзапрос и присоединить его к вашим условиям предиката.

2

Укажите присоединиться Тип:

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

 Смежные вопросы

  • Нет связанных вопросов^_^