Java JPA Criteria API - 如何添加 JOIN 子句(尽可能通用的句子)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3424696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 00:40:24  来源:igfitidea点击:

JPA Criteria API - How to add JOIN clause (as general sentence as possible)

javaapijoinjpa-2.0criteria-api

提问by Mandor

I am trying to construct queries dynamically, and my next target is add JOIN clauses (I don't know how can I use the API).

我正在尝试动态构造查询,我的下一个目标是添加 JOIN 子句(我不知道如何使用 API)。

By now, for example, this code work for me :

例如,到目前为止,这段代码对我有用:

...
Class baseClass;   
...
CriteriaBuilder cb = JpaHandle.get().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(this.baseClass);
Root entity_ = cq.from(this.baseClass); 
Predicate restrictions = null;
...
restrictions = cb.conjunction();
restrictions = cb.and(restrictions, entity_.get("id").in(this.listId));
...
cq.where(restrictions);
...
Query qry = JpaHandle.get().createQuery(cq);

(Note : JpaHandle is from wicket-JPA implementation)

(注意:JpaHandle 来自 wicket-JPA 实现)

My desire is add JOIN clause (as generical as possible)!

我的愿望是添加 JOIN 子句(尽可能通用)!

I have the particular annotations in the classes (this.baseClass)

我在类中有特定的注释(this.baseClass)

For example :

例如 :

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "assay_id", nullable = false)

So,Is there a way to something like this in standard JPA ? (Note : this don't compile)

那么,在标准 JPA 中有没有办法做到这一点?(注意:这不编译)

Here a practical fail aproaches :

这里有一个实际的失败方法:

...
Join<Experiment,Assay> experimentAssays = entity_.join( entity_.get("assay_id") );

Or like that :

或者像这样:

...
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> c = q.from(Customer.class);
SetJoin<Customer, PurchaseOrder> o = c.join(Customer_.orders);

For me, if it could be more generical as possible it will be great... :

对我来说,如果它可以更通用,那就太好了......:

...
Join joinClause = entity_join(entity_.get("assay_id"), entity2_.get("id"));

Of course, I have the particular annotations in the classes (this.baseClass)

当然,我在类中有特定的注释(this.baseClass)

Thank you for your time. I'll appreciate all kind of comments!

感谢您的时间。我会感谢所有类型的评论!

回答by Pascal Thivent

Maybe the following extract from the Chapter 23 - Using the Criteria API to Create Queriesof the Java EE 6 tutorial will throw some light (actually, I suggest reading the whole Chapter 23):

也许以下摘自第 23 章 - 使用 Criteria API 来创建Java EE 6 教程的查询会有所启发(实际上,我建议阅读整个第 23 章):

Querying Relationships Using Joins

For queries that navigate to related entity classes, the query must define a join to the related entity by calling one of the From.joinmethods on the query root object, or another joinobject. The join methods are similar to the JOINkeyword in JPQL.

The target of the join uses the Metamodel class of type EntityType<T>to specify the persistent field or property of the joined entity.

The join methods return an object of type Join<X, Y>, where Xis the source entity and Yis the target of the join.

Example 23-10 Joining a Query

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);

Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);

Joins can be chained together to navigate to related entities of the target entity without having to create a Join<X, Y>instance for each join.

Example 23-11 Chaining Joins Together in a Query

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
EntityType<Owner> Owner_ = m.entity(Owner.class);

Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = cq.join(Pet_.owners).join(Owner_.addresses);

使用联接查询关系

对于导航到相关实体类的查询,查询必须通过调用From.join查询根对象或另一个join对象上的方法 之一来定义与相关实体的连接。连接方法类似于JOINJPQL 中的关键字。

EntityType<T>联接的目标使用类型的元模型类 来指定联接实体的持久字段或属性。

连接方法返回一个类型为 的对象Join<X, Y>,其中X是源实体,Y是连接的目标。

示例 23-10 加入查询

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);

Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);

连接可以链接在一起以导航到目标实体的相关实体,而无需Join<X, Y>为每个连接创建实例。

示例 23-11 在查询中链接联接

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
EntityType<Owner> Owner_ = m.entity(Owner.class);

Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = cq.join(Pet_.owners).join(Owner_.addresses);

That being said, I have some additional remarks:

话虽如此,我还有一些补充说明:

First, the following line in your code:

首先,代码中的以下行:

Root entity_ = cq.from(this.baseClass);

Makes me think that you somehow missed the Static Metamodel Classes part. Metamodel classes such as Pet_in the quoted example are used to describe the meta informationof a persistent class. They are typically generatedusing an annotation processor (canonical metamodel classes) or can be written by the developer (non-canonical metamodel). But your syntax looks weird, I think you are trying to mimic something that you missed.

让我觉得你不知何故错过了静态元模型类部分。Pet_引用示例中的元模型类用于描述持久类的元信息。它们通常产生使用注释处理器(规范元模型类),或者可以由开发者(被写入非规范元模型)。但是您的语法看起来很奇怪,我认为您正在尝试模仿您错过的东西。

Second, I really think you should forget this assay_idforeign key, you're on the wrong path here. You really need to start to think object and association, not tables and columns.

其次,我真的认为你应该忘记这个assay_id外键,你在这里走错了路。您确实需要开始考虑对象和关联,而不是表和列。

Third, I'm not really sure to understand what you mean exactly by adding a JOIN clause as generical as possibleand what your object model looks like, since you didn't provide it (see previous point). It's thus just impossible to answer your question more precisely.

第三,我不确定通过添加尽可能通用JOIN 子句以及您的对象模型的样子来确切理解您的意思,因为您没有提供它(请参阅上一点)。因此,无法更准确地回答您的问题。

To sum up, I think you need to read a bit more about JPA 2.0 Criteria and Metamodel API and I warmly recommend the resources below as a starting point.

总而言之,我认为您需要阅读更多关于 JPA 2.0 Criteria 和 Metamodel API 的内容,我热烈推荐以下资源作为起点。

See also

也可以看看

Related question

相关问题

回答by user793442

You don't need to learn JPA. You can use my easy-criteria for JPA2 (https://sourceforge.net/projects/easy-criteria/files/). Here is the example

你不需要学习JPA。您可以将我的简单标准用于 JPA2 ( https://sourceforge.net/projects/easy-criteria/files/)。这是例子

CriteriaComposer<Pet> petCriteria CriteriaComposer.from(Pet.class).
where(Pet_.type, EQUAL, "Cat").join(Pet_.owner).where(Ower_.name,EQUAL, "foo");

List<Pet> result = CriteriaProcessor.findAllEntiry(petCriteria);

OR

或者

List<Tuple> result =  CriteriaProcessor.findAllTuple(petCriteria);

回答by Christophe Opoix

Actually you don't have to deal with the static metamodel if you had your annotations right.

实际上,如果您的注释正确,您就不必处理静态元模型。

With the following entities :

具有以下实体:

@Entity
public class Pet {
  @Id
  protected Long id;
  protected String name;
  protected String color;
  @ManyToOne
  protected Set<Owner> owners;
}

@Entity
public class Owner {
  @Id
  protected Long id;
  protected String name;
}

You can use this :

你可以使用这个:

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> petMetaModel = m.entity(Pet.class);

Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(petMetaModel.getSet("owners", Owner.class));

回答by Chris Harris

Warning! There's a numbers of errors on the Sun JPA 2 example and the resulting pasted content in Pascal's answer. Please consult this post.

警告!Sun JPA 2 示例和 Pascal 的答案中产生的粘贴内容存在许多错误。请参阅此帖子

This post and the Sun Java EE 6 JPA 2 example really held back my comprehension of JPA 2. After plowing through the Hibernate and OpenJPA manuals and thinking that I had a good understanding of JPA 2, I still got confused afterwards when returning to this post.

这篇文章和 Sun Java EE 6 JPA 2 示例确实阻碍了我对 JPA 2 的理解。在翻阅了 Hibernate 和 OpenJPA 手册并认为我对 JPA 2 有了很好的理解之后,我仍然在返回这篇文章时感到困惑.