Referencing with this answer to this correlated thread,
the trick posted by ehrhardt works fine.
But, what I have to do if I have to join with multiple entities? for example:
List<Person> peopleWithBooks = session.createSQLQuery(
"select {p.*}, {b.*}, {m.*} from person p, book b, magazine m where <complicated join>")
.addEntity("p", Person.class)
.addJoin("b", "p.books")
.addJoin("m", "p.magazines")
.addEntity("p", Person.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
Hibernate aggregates right the first join, but not the second (magazine entities are not grouped).
There are any tricks or there is a limit to join with only one correlated entity?
And if I have to join with entities that have sub entities? (my goal is to retrieve all selected data with only one custom query)
Related
I need your help.
I've 2 tables with a join table to get ManyToMany relationship as below :
Table schema
In JAVA with JPA, I'm able for one User to get List<Group>, or for a Group to get List<User>.
Is there a way to get one entity with List<User> AND List<Group> like you can do with SQL :
SELECT * FROM USER_GROUP
INNER JOIN USERS ON USERS.ID = USER_GROUP.USER_ID
INNER JOIN GROUPS ON GROUPS.ID = USER_GROUP.GROUP_ID
WHERE USERS.USER_NAME LIKE ....
Thx all for your help :)
I want to ignore default Join Restriction in createAlias. I have a OnetoOne relationship.
My Problem is Hibernate generates default restriction for the join relationship.
Pojo
Note : No column for diagnosticTemplate in charge table.
Charge.java
#OneToOne(mappedBy = "charge")
private DiagnosticTemplate diagnosticTemplate;
DiagnosticTemplate.java
#OneToOne
#JoinColumn(name = "charge")
#Exclude
private Charge charge;
Query
select
*
from
charges c
inner join diagnostic_template dt
on (dt.charge = c.id and dt.status=1) or (dt.status=0)
Criteria
Criteria criteria = getSession().createCriteria(Charge.class, "charge")
.createAlias("charge.diagnosticTemplate", "diagnosticTemplate",
JoinType.INNER_JOIN,
Restrictions.or(
Restriction.and(Restrictions.eqProperty("charge.id",
"diagnosticTemplate.charge"),
Restrictions.eq("diagnosticTemplate.status",true)),
Restrictions.eq("diagnosticTemplate.status",false) ))
Hibernate Query
select
*
from
charges c
inner join diagnostic_template dt
on dt.charge = c.id and (dt.charge = c.id and dt.status=1) or (dt.status=0)
How to avoid this condition? or anything wrong with my relationship?
Please help..!
When you join a charge with charge.diagnosticTemplate, it means that Hibernate will try to lookup a DiagnosticTemplate that is linked with this charge. Thus, the generated condition dt.charge = c.id does make sense.
Remember that you have define the relationship using foreign key. So, soft relation like dt.status=0 cannot be understood by Hibernate.
If you still wish to achieve you query, you can consider joining the two instance indirectly (not using association path). Refer to How to join Multiple table using hibernate criteria where entity relationship is not direct?.
I'm fighting this whole day and I can't figure it out. I'm JPA beginner, so for now Criteria API is a nightmare for me. The problem:
I have 3 entities: Policy, Customer, Insurer. Policy has references to a Customer and an Insurer (eager fetch here). Customer has list of policies, so do Insurer (lazy fetch here).
I'm trying to find all policies in a way described below (SQL):
SELECT * FROM POLICY as p WHERE
p.CUSTOMER_ID IN (SELECT ID FROM CUSTOMER as c WHERE [customerPredicates])
AND
p.INSURER_ID IN (SELECT ID FROM INSURER as i WHERE [insurerPredicates])
AND
[policyPredicates]
Where CUSTOMER_ID / INSURER_ID are JoinColumns generated from #ManyToOne relationships in Policy.
customerPredicates / insurerPredicates / policyPredicates are lists of predicates ('where' conditions prepared from given search criteria).
How can I achieve that in Criteria API? What are rules / good practices for creating this kind of queries?
Try to rewrite the SQL first to use JOINS
SELECT *
FROM POLICY as p
INNER JOIN CUSTOMER as c ON p.CUSTOMER_ID = c.ID
INNER JOIN INSURER as i ON p.INSURER_ID = i.ID
WHERE [customerPredicates])
AND
[insurerPredicates])
AND
[policyPredicates]
The all you need is criteria api is to get main criteria (for the Policy entity) and create aliases for Customer entity and Insurer entity.
Criteria criteria = session.createCriteria(Policy.class, "p");
criteria.setFetchMode("p.Customer", FetchMode.JOIN);
criteria.createAlias("p.Customer", "c");
and add your restriction to the "c" alias for Customer.
And the same for Insurer
I have two unrelated tables, each one with field email. I need a query which introduces column taken from second table if emails match or will be null if no match is found. In SQL this is easy:
SELECT tableA.id, tableA.email, tableB.name
FROM tableA
LEFT JOIN tableB ON tableA.email=tableB.email
ORDER BY tableB.name
Unfortunately JPA doesn't allow joins over unrelated entities so I converted it to:
SELECT tableA.id, tableA.email,
(SELECT tableB.name FROM tableB WHERE tableB.email=tableA.email) AS aname
FROM tableA
ORDER BY aname
Now, it works as JPA query but we are using Query DSL so off we go to converting it:
JPQLQuery query = new JPAQuery(em);
List<Dto> items=query.from(qTableA)
.list(new QDto(qTableA.id, qTableA.email,
new JPASubQuery().from(qTableB)
.where(qTableB.email.eq(qTableA.email)).unique(qTableB.name)))
It works but now I have no idea how to implement sorting and filtering by field introduced by subquery.
Dto is a POJO used to collect results, QDto is a class autogenerated from Dto.
Question is: how to join two unrelated tables using Query DSL and JPA and avoiding native SQL? Is it possible? Sorting and filtering on fields from tableA and tableB.name is a requirement.
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
I have multiple entities that are queried via JPA2 Criteria Query.
I am able to join two of these entities and get the result at once:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<LadungRgvorschlag> criteriaQuery = criteriaBuilder.createQuery(LadungRgvorschlag.class);
Root<LadungRgvorschlag> from = criteriaQuery.from(LadungRgvorschlag.class);
Join<Object, Object> ladung = from.join("ladung");
from.fetch("ladung", JoinType.INNER);
Then i try to join an additional table like that:
ladung.join("ladBerechnet");
ladung.fetch("ladBerechnet", JoinType.LEFT);
i get the following error:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias3,role=null,tableName=ladberechnet,tableAlias=ladberechn3_,origin=ladungen ladung1_,columns={ladung1_.id ,className=de.schuechen.beans.tms.master.LadBerechnet}}] [select generatedAlias0 from de.schuechen.beans.tms.master.LadungRgvorschlag as generatedAlias0 inner join generatedAlias0.ladung as generatedAlias1 inner join generatedAlias1.ladBerechnet as generatedAlias2 left join fetch generatedAlias1.ladBerechnet as generatedAlias3 inner join fetch generatedAlias0.ladung as generatedAlias4 where ( generatedAlias0.erledigt is null ) and ( generatedAlias0.belegart in (:param0, :param1) ) and ( generatedAlias1.fzadresse in (:param2, :param3) ) and ( generatedAlias1.zudatum<=:param4 ) and ( 1=1 ) order by generatedAlias0.belegart asc, generatedAlias1.fzadresse asc, generatedAlias1.zudatum asc, generatedAlias1.zulkw asc]
How can i tell JPA/Hibernate, that it should select all the entities at once?
With JPA 'some dialects of JPA' you can chain join fetches, but I don't think you can/should do both a join and a join fetch.
For instance, if we have a Program that has a one-to-many relation to a Reward that has a relation to a Duration, the following JPQL would get a specific instance with the rewards and duration pre-fetched:
SELECT DISTINCT
program
FROM
Program _program
LEFT JOIN FETCH
_program.rewards _reward
LEFT JOIN FETCH
_reward.duration _duration
WHERE
_program.id = :programId
}
With the equivalent Criteria code:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Program> criteriaQuery = criteriaBuilder.createQuery(Program.class);
Root<Program> root = criteriaQuery.from(Program.class);
Fetch<Program, Reward> reward = root.fetch("rewards", JoinType.LEFT);
Fetch<Reward, Duration> duration = reward.fetch("duration", JoinType.LEFT);
criteriaQuery.where(criteriaBuilder.equal(root.get("id"), programId));
TypedQuery<program> query = entityManager.createQuery(criteriaQuery);
return query.getSingleResult();
Note that the intermediate variables reward and duration are not needed here, but they're just for informational purposes. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) would have the same effect.
What it comes to JPA, you cannot chain join fetches in Criteria API queries (citation from specification):
An association or attribute referenced by the fetch method must be
referenced from an entity or embeddable that is returned as the result
of the query. A fetch join has the same join semantics as the
corresponding inner or outer join, except that the related objects are
not top-level objects in the query result and cannot be referenced
elsewhere by the query.
And it is also not supported in JPQL queries:
The association referenced by the right side of the FETCH JOIN clause
must be an association or element collection that is referenced from
an entity or embeddable that is returned as a result of the query.
It is not permitted to specify an identification variable for the
objects referenced by the right side of the FETCH JOIN clause, and
hence references to the implicitly fetched entities or elements cannot
appear elsewhere in the query.
With HQL it seems to be possible: Hibernate documentation EclipseLink does not provide such a extension, so syntax of following query is accepted by Hibernate, but not by EclipseLink:
SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc
In EclipseLink same can be done via query hints.