Nano Hash - криптовалюты, майнинг, программирование

Как мне использовать CriteriaBuilder для написания левого внешнего соединения, когда отношение идет другим путем?

Я использую JPA 2.0, Hibernate 4.1.0.Final и MySQL 5.5.37. У меня есть следующие два объекта …

@Entity
@Table(name = "msg")
public class Message
{

    @Id
    @NotNull
    @GeneratedValue(generator = "uuid-strategy")
    @Column(name = "ID")
    private String id;

    @Column(name = "MESSAGE", columnDefinition="LONGTEXT")
    private String message;

а также

@Entity
@Table(name = "msg_read", uniqueConstraints = { @UniqueConstraint(columnNames = { "MESSAGE_ID", "RECIPIENT" }) })
public class MessageReadDate
{

    @Id
    @NotNull
    @GeneratedValue(generator = "uuid-strategy")
    @Column(name = "ID")
    private String id;

    @ManyToOne
    @JoinColumn(name = "RECIPIENT", nullable = false, updatable = true)
    private User recipient;

    @ManyToOne
    @JoinColumn(name = "MESSAGE_ID", nullable = false, updatable = true)
    private Message message;

    @Column(name = "READ_DATE")
    private java.util.Date readDate;

Используя CriteriaBuilder, как бы я написал это

SELECT DISTINCT m.*
FROM msg AS m
LEFT JOIN msg_read AS mr
        ON mr.message_id = m.id AND mr.recipient = 'USER1'

? Моя проблема в том, что в моем объекте Message нет поля «msg_read», и я не уверен, как указать часть «И» левого внешнего соединения в CriteriaBuilder.


  • mr.recipient = 'USER1' вообще работает? 13.09.2014
  • Для добавления дополнительных условий к условие соединения, которое является частью JPA 2.1. Следовательно, он доступен только в Hibernate 4.3.x и более поздних версиях, если вы не используете простой Hibernate, который поддерживает предложение with для того же. 13.09.2014

Ответы:


1

Вы можете сделать что-то вроде этого.

final Root<Message> messageRoot = criteriaQuery.from(Message.class);
Join<Message, MessageReadDate> join1 = messageRoot .join("joinColumnName", JoinType.LEFT);

Predicate predicate = criteriaBuilder.equal(MessageReadDate.<String> get("recipient"), recepientValue;
criteria.add(predicate);
criteriaQuery.where(predicate);
criteriaQuery.distinct(true);

Я надеюсь, что это решит ваш вопрос.

13.09.2014
  • Привет, Вы переформулируете мою проблему - я не могу использовать предложение 'messageRoot .join(joinColumnName', потому что у меня нет имени joinColumn из Message -> MessageReadDate, только наоборот. Это проблема, которую я пытается преодолеть. 22.09.2014

  • 2

    Если между двумя объектами нет явной связи (двунаправленной ассоциации), то условие JOIN помещается в предложение WHERE.

    Подход JPQL может выглядеть следующим образом:

    SELECT DISTINCT m 
    FROM Message m, MessageReadDate mr 
    WHERE m.id = mr.message.id AND mr.recipient.name = 'USER1'
    

    следовательно, Criteria API может выглядеть следующим образом:

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Message> cq = cb.createQuery(Message.class);
    Root<Message> m = cq.from(Message.class);
    Root<MessageReadDate> mr = cq.from(MessageReadDate.class);
    
    Predicate p1 = cb.equal(mr.get("recipient").get("name"), cb.literal("USER1"));
    Predicate p2 = cb.equal(mr.get("message").get("id"), m.get("id"));
    Predicate criteria = cb.conjunction();
    criteria = cb.and(criteria, p1);
    criteria = cb.and(criteria, p2);
    
    cq.where(criteria);
    cq.select(m).distinct(true);
    
    List<Message> messages = em.createQuery(cq).getResultList();
    
    15.09.2014
  • Привет, я не думаю, что SELECT DISTINCT m FROM Message m, MessageReadDate mr WHERE m.id = mr.message.id AND mr.recipient.name = 'USER1' совпадает с тем, что было в моем вопросе, SELECT * FROM msg AS m LEFT JOIN msg_read AS mr ON mr.message_id = m.id AND mr.recipient = 'USER1'. Я получаю некоторые неправильные результаты, применяя эту логику. 22.09.2014
  • @Dave: Как определяется ваша сущность User? 25.09.2014
  • Разве это решение не выполняет внутреннее соединение? Как можно сделать то же самое, но с внешним соединением? 10.06.2016
  • смотри мой ответ ниже 17.09.2018

  • 3

    вы не можете сделать это в JPA 2.0 (в запросах критериев). вам нужно либо сделать это через JPQL, либо перейти на JPA 2.2. в JPA 2.2 они представили оператор .on(), который позволяет выполнять произвольные внешние соединения.

    14.09.2018

    4

    javax.persistence.criteria.Join.on() взято из JPA 2.1. Тем не менее, вам не разрешено присоединяться к несвязанным объектам, как указано разработчиками Hibernate:

    https://vladmihalcea.com/how-to-join-unrelated-entities-with-jpa-and-hibernate/

    Присоединение несвязанных сущностей возможно только при использовании JPQL или HQL. Эта функция недоступна при использовании JPA Criteria API.

    Единственный способ сделать соединение — добавить отсутствующую ассоциацию (вероятно, LAZY) к объекту, потому что Criteria API не позволяет: root.join("id", JoinType.LEFT), это не удается с:

    org.hibernate.query.criteria.internal.BasicPathUsageException:
    Cannot join to attribute of basic type
    

    и безуспешно переопределять соединение с Join.on().

    Другой способ — использовать JPQL. Если ваш запрос динамический - используйте String.format() небезопасный, но старый подход для построения запроса JPQL ))

    Альтернативный подход состоит в том, чтобы основать root на другом объекте и сделать ПРАВОЕ ПРИСОЕДИНЕНИЕ!

    07.07.2020

    5

    Сущность «Сообщение» не имеет никакой ссылки на MessageReadDate. Поэтому было бы лучше использовать начало «MessageReadDate» в качестве корня, а затем перейти к «Сообщению».

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Message> query = cb.createQuery(Message.class);
    Root<MessageReadDate> root = query.from(MessageReadDate.class);
    final Join<MessageReadDate, Message> msg = root.join("message");
    
    query.select(root);
    query.where(cb.equal(root.get("recipient"),
                                  "USER1"));
    List<Message> = em.createQuery(query)
                      .getResultList();
    
    26.03.2021
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..