问题
Two database tables have a foreign key relationship.
They are mapped to two entities A and B by JPA, but the join columns are manually removed from the entities, so in JPA world classes A and B are not related and you cannot navigate from one to the other through a field/property.
Using the JPA Criteria API, is it possible to create a query which joins the two tables?
All examples I found on internet uses the join column to achieve the goal, but, as stated above, it was removed from the code because most time I'm not interested in the relationship between A and B and I'm afraid about possible overhead.
回答1:
First: Foreign key relationship are not only for navigating. They mainly serve to ensure that no spurious values are introduced in the relationship. They also may help the database for query optimization. I would advise you to reconsider that.
Anyway, for creating a query that uses several unrelated entities, you need to put them as from
(root
) entities (as you would do in SQL or JPQL)
SELECT .... FROM Link l, Training t WHERE l.attribute = t.attribute;
Root<Link> rootLink = criteriaQuery.from(Link.class);
Root<Training> rootTraining = criteriaQuery.from(Training.class);
...
criteriaQuery.where(
criteriaBuilder.equal(rootLink.get(link_.linkAttribute), trainingLink));
回答2:
Join on unrelated entities is not covered by latest JPA spec (2.1)
However Hibernate 5.1.0+ and EclipseLink 2.4.0+ support ad hoc joins. http://blog.anthavio.net/2016/03/join-unrelated-entities-in-jpa.html
Another possibility is native query http://www.oracle.com/technetwork/articles/vasiliev-jpql-087123.html
回答3:
As I explained in this article, since Hibernate 5.1, you can join unrelated entities when using JPQL and HQL:
Tuple postViewCount = entityManager.createQuery(
"select p as post, count(pv) as page_views " +
"from Post p " +
"left join PageView pv on p.slug = pv.slug " +
"where p.title = :title " +
"group by p", Tuple.class)
.setParameter("title", "Presentations")
.getSingleResult();
However, this feature is not available in Criteria API, as that would require an API extension.
The solution
While you could try to use two Root
objects and emulate the INNER JOIN via WHERE clause predicates, the resulting SQL is not the best way to solve this issue.
You should consider using jOOQ as, besides giving you the ability to join tables in any possible ways, you can also fetch entities if you pass the generated SQL query to the JPA createNativeQuery method.
回答4:
You could use the JPA Criteria implementation of Blaze-persistence that translates to JPQL/HQL and offers that feature as extension to the JPA Criteria API.
Look for "Blaze-Persistence JPA-Criteria module dependencies" in the readme: https://github.com/Blazebit/blaze-persistence/blob/master/README.md
Then use BlazeCriteriaBuilder cb = BlazeCriteria.get(criteriaBuilderFactory)
and finally blazeCriteriaQuery.getCriteriaBuilder(entityManager)
to render the JPA Criteria Query object.
来源:https://stackoverflow.com/questions/17106434/how-to-join-unrelated-entities-with-the-jpa-criteria-api