问题
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