How do I use CriteriaBuilder to write a left outer join when relationship goes the other way?

拈花ヽ惹草 提交于 2019-12-09 03:13:58

问题


I’m using JPA 2.0, Hibernate 4.1.0.Final and MySQL 5.5.37. I have the following two entities …

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

and

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

Using CriteriaBuilder, how would I write this

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

? My problem is that there is no field “msg_read” in my Message entity, and I’m not sure how to specify the “AND” part of the left outer join in CriteriaBuilder.


回答1:


You can do something like this.

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

I hope this will resolve your query.




回答2:


If there is no explicit relationship between two entities (no bidirectional association) then JOIN condition is placed in the WHERE clause.

JPQL approach might look as follows:

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

consequently, Criteria API might look as follows:

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



回答3:


you can't do this in JPA 2.0 (in criteria queries). you either have to do it via JPQL, or upgrade to JPA 2.2. in JPA 2.2 they introduced the .on() operator that allows for arbitrary outer joins.



来源:https://stackoverflow.com/questions/25788965/how-do-i-use-criteriabuilder-to-write-a-left-outer-join-when-relationship-goes-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!