Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa 当关系走向另一个方向时,如何使用CriteriaBuilder编写左外部联接?_Jpa_Left Join_Jpa 2.0_Criteria_Builder - Fatal编程技术网

Jpa 当关系走向另一个方向时,如何使用CriteriaBuilder编写左外部联接?

Jpa 当关系走向另一个方向时,如何使用CriteriaBuilder编写左外部联接?,jpa,left-join,jpa-2.0,criteria,builder,Jpa,Left Join,Jpa 2.0,Criteria,Builder,我正在使用JPA2.0、Hibernate4.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 = "MES

我正在使用JPA2.0、Hibernate4.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;

使用CriteriaBuilder,我将如何编写

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

??我的问题是,我的消息实体中没有字段“msg_read”,我不确定如何在CriteriaBuilder中指定左侧外部联接的“and”部分。

您可以这样做

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);
final Root messageRoot=criteriaQuery.from(Message.class);
Join join1=messageRoot.Join(“joinColumnName”,JoinType.LEFT);
谓词谓词=criteriaBuilder.equal(MessageReadDate.get(“收件人”),recepientValue;
添加(谓词);
criteriaQuery.where(谓词);
criteriaQuery.distinct(true);

我希望这将解决您的查询。

如果两个实体之间没有明确的关系(没有双向关联),那么连接条件将放在WHERE子句中

JPQL方法可能如下所示:

选择DISTINCT m
来自消息m,消息ReadDate先生
其中m.id=mr.message.id和mr.recipient.name='USER1'
因此,API标准可能如下所示:

CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery cq=cb.createQuery(Message.class);
根m=cq.from(Message.class);
根mr=cq.from(MessageReadDate.class);
谓词p1=cb.equal(mr.get(“接收方”).get(“名称”),cb.literal(“用户1”);
谓词p2=cb.equal(mr.get(“message”).get(“id”)、m.get(“id”);
谓词条件=cb.conjunction();
标准=cb和(标准,p1);
标准=cb和(标准,p2);
cq.其中(标准);
cq.select(m).distinct(true);
List messages=em.createQuery(cq.getResultList();

在JPA2.0(在标准查询中)中无法执行此操作。您必须通过JPQL执行此操作,或者升级到JPA2.2。在JPA2.2中,他们引入了允许任意外部联接的.on()运算符。

javax.persistence.criteria.Join.on()
来自JPA 2.1。但仍不允许加入Hibernate开发人员声明的不相关实体:

只有在使用JPQL或HQL时,才能连接不相关的实体。在使用JPA标准API时,此功能不可用

创建联接的唯一方法是向实体添加缺少的关联(可能是
惰性的
),因为标准API不允许:
root.join(“id”,JoinType.LEFT)
,它失败于:

org.hibernate.query.criteria.internal.BasicPathUsageException:
Cannot join to attribute of basic type
而且没有运气用
join.on()
覆盖join

另一种方法是使用JPQL。如果您的查询是动态的,请使用
String.format()
不安全但旧的方法来构建JPQL查询)


另一种方法是以其他实体为根并进行正确的连接

实体“Message”没有对MessageReadDate的任何引用。 因此,最好使用start'MessageReadDate'作为根目录,然后转到'Message'

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();
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery=cb.createQuery(Message.class);
Root=query.from(MessageReadDate.class);
final Join msg=root.Join(“消息”);
查询。选择(根);
query.where(cb.equal(root.get)(“收件人”),
“用户1”);
List=em.createQuery(查询)
.getResultList();

mr.recipient='USER1'是否仍然有效?该子句可用于将附加条件附加到作为JPA 2.1一部分的连接条件。因此,它仅在Hibernate 4.3.x及更高版本中可用,除非您使用支持
with
子句的普通Hibernate。您好,您正在重复我的问题--我不能使用“messageRoot.join”(“joinColumnName”)子句,因为我没有“joinColumn”name from Message->MessageReadDate,仅适用于toher。这是我试图克服的问题。您好,我不认为“选择m from Message m,MessageReadDate mr,其中m.id=mr.Message.id和mr.recipient.name='USER1'”与我的问题相同,“选择*FROM msg AS m LEFT JOIN msg_read AS mr ON mr.message_id=m.id和mr.recipient='USER1'”。应用此逻辑,我得到了一些错误的结果。@Dave:您的
用户
实体是如何定义的?此解决方案不执行内部联接吗?除了外部联接之外,如何执行相同的操作?请参阅下面的答案
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();