Подтвердить что ты не робот

Как создать соединение 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 для создания запроса, как в первом примере?

4b9b3361

Ответ 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));

Ответ 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;