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).
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)
My desire is add JOIN clause (as generical as possible)!
I have the particular annotations in the classes (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)
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)
Thank you for your time. I'll appreciate all kind of comments!
Maybe the following extract from the Chapter 23 - Using the Criteria API to Create Queries of the Java EE 6 tutorial will throw some light (actually, I suggest reading the whole Chapter 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.join
methods
on the query root object, or another
join
object. The join methods are
similar to the JOIN
keyword 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 X
is the
source entity and Y
is 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);
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 information of a persistent class. They are typically generated using 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.
Second, I really think you should forget this assay_id
foreign key, you're on the wrong path here. You really need to start to think object and association, not tables and columns.
Third, I'm not really sure to understand what you mean exactly by adding a JOIN clause as generical as possible and 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.
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.
See also
- the section 6.2.1 Static Metamodel Classes in the JPA 2.0 specification
- Dynamic, typesafe queries in JPA 2.0
- Using the Criteria API and Metamodel API to Create Basic Type-Safe Queries
Related question
- How to generate JPA 2.0 metamodel?
Actually you don't have to deal with the static metamodel if you had your annotations right.
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));
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
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);
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.
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.