Как создать соединение CriteriaBuilder с пользовательским условием "on"?
Я хочу сделать запрос, когда я присоединяюсь к двум таблицам, используя CriteriaBuilder. В MySQL запрос, который я пытаюсь сделать, будет выглядеть так:
SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
AND item.type_id = 1
Я хочу получить все заказы, и если у них есть элемент типа № 1, я хочу присоединиться к этому элементу. Однако, если ни один элемент типа №1 не найден, я все равно хочу получить заказ. Я не могу понять, как это сделать с помощью CriteriaBuilder. Все, что я знаю, как это сделать:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT);
cq.select(order);
cq.where(cb.equal(type.get(Type_.id), 1));
Этот запрос сломан, так как он приводит к чему-то подобному в MySQL:
SELECT * FROM order
LEFT JOIN item
ON order.id = item.order_id
WHERE item.type_id = 1
Результат будет содержать только заказы с элементами типа №1. Заказы без исключены. Как я могу использовать CriteriaBuilder для создания запроса, как в первом примере?
Ответы
Ответ 1
Это возможно при использовании метода on
Join<Z, X> on(Predicate... restrictions);
Вот как:
Root<Order> order = cq.from(Order.class);
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT);
item.on(cb.equal(item.get(Item_.type), 1));
Ответ 2
Я думаю, что это та же проблема, что и в этом вопросе. Похоже, это невозможно в CriteriaBuilder. Это возможно в Hibernate Criteria API, но это, вероятно, вам не поможет.
API-интерфейс JPA: несколько условий для LEFT JOIN
Ответ 3
Я знаю, что этот вопрос давно зашел, но в последнее время у меня была такая же проблема, и я нашел это решение на форуме Oracle, я скопировал и вставил на всякий случай, когда ссылка больше не доступна.
MiguelChillitupaArmijos 29-abr-2011 1:41 (en respuesta a 840578) Подумайте вы должны использовать что-то вроде:
em.createQuery("SELECT DISTINCT e.Id" +
" from Email e " +
" left join e.idEmailIn e2 *with* e2.responseType = 'response'" +
" where e.type = 'in' and e.responseMandatory = true").getSingleResult();
Это ссылка.
Критерии JPA: LEFT JOIN с условием AND
Ответ 4
Существует обходное решение, если вы используете Hibernate 3.6 с JPA 2.0
Это не лучшее решение, но оно отлично подходит для меня.
Я дублирую объект с аннотацией @Where hibernate. Это означает, что каждый раз, когда вы используете соединение с этим сущностью, hibernate добавляет дополнительное условие в оператор соединения при сгенерированном SQL.
Например, изначально мы имеем следующий пример:
@Entity
@Table(name = "PERSON")
public class Person {
@Id
@Column(name = "PERSON_ID")
private Long id;
@Id
@Column(name = "PERSON_NAME")
private String name;
@OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
private Set<Address> addresses;
}
@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@Column(name = "ADDRESS_ID")
private Long id;
@Id
@Column(name = "ADDRESS_STREET")
private String street;
@ManyToOne
@JoinColumn(name = "PERSON_ID")
private Person person;
}
Чтобы добавить дополнительные условия в критерии Join, нам нужно дублировать отображение Address @Entity, добавив @Where annotation @Where (clause = "ADDRESS_TYPE_ID = 2" ).
@Entity
@Table(name = "ADDRESS")
@Where(clause = " ADDRESS_TYPE_ID = 2")
public class ShippingAddress {
@Id
@Column(name = "ADDRESS_ID")
private Long id;
@Id
@Column(name = "ADDRESS_STREET")
private String street;
@OneToOne
@JoinColumn(name = "PERSON_ID")
private Person person;
}
Кроме того, нам нужно добавить ассоциацию дублирования сопоставления для нового объекта.
@Entity
@Table(name = "PERSON")
public class Person {
@Id
@Column(name = "PERSON_ID")
private Long id;
@Id
@Column(name = "PERSON_NAME")
private String name;
@OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
private Set<Address> addresses;
@OneToOne(mappedBy = "person")
private ShippingAddress shippingAddress;
}
Наконец, вы можете использовать соединение с этим конкретным объектом в ваших критериях:
PersonRoot.join(Person_.shippingAddress, JoinType.LEFT);
Сбой Hibernate Snippet SQL должен выглядеть следующим образом:
left outer join
address shippingadd13_
on person11_.person_id=shippingadd13_.person_id
and (
shippingadd13_.ADDRESS_TYPE_ID = 2
)
Ответ 5
Предложение ON поддерживается в версии Hibernate 4.3, всем известно, есть ли проблема индексации параметров между индексом параметров дополнительных пользовательских условий с индексом существующих фильтров отображения при выполнении внешнего соединения с предложением ON?
Используя класс сущности Person ниже в качестве примера, скажем, я добавляю этот фильтр, чтобы ограничить типы адресов, и фильтр включен для заполнения предложения IN. Индекс параметра для предложения IN вызовет проблему [2], когда я добавлю дополнительные условия (например, используя столбец "улица" ) в предложении ON. Это известная проблема?
[1] @Filter (name = "addressTypes", condition = "ADDRESS_TYPE in (: supportedTypes)" )
[2]
Вызвано: ERROR 22018: Неверный формат символьной строки для типа BIGINT. private Set address;