I have two entities, whith OneToMany relationship:
class Parent {
int parentId;
Set<Children> children;
}
class Child {
int childId;
}
and the following HQL query:
"SELECT p.children FROM Parent p left join p.children as c WHERE p.id=:pid AND c.id:=cid"
is returning me all children of the parent with given id, while I would expect only a child with id matching given child id. What am I doing wrong here?
You need to use inner join instead of left join.
Try either of the below, not sure of exact syntax.
SELECT p.children FROM Parent p inner join p.children as c WHERE p.id=:pid AND c.id:=cid
or
SELECT p.children FROM Parent p, p.children as c WHERE p.id=:pid AND c.id:=cid
Related
Related questions don't seem to cover exactly what I'm trying to do.
#Repository
public interface FooRepository extends JpaRepository<FooEntity, Integer> {
#Query("select child from BarEntity p inner join p.fooColumn child where p = :parent")
Page<FooEntity> findBy(#Param("parent") HasFooInterface parent, Pageable pageable);
}
This is a query that returns pages of FooEntity where BarEntity is the parent in the relationship.
What I want, is for the query to be defined in a generic way. The parent object that's an instance of HasFooInterface will always be an entity with a relation to Foo (BarEntity in this example).
So where it says #Query("select child from BarEntity p inner join p.fooColumn child where p = :parent")
I want to be able to parameterize that "BarEntity" to be
#Query("select child from _?parent.getClass.getSimpleName()?_ p inner join p.fooColumn child where p = :parent")
What can I replace here to get the functionality I need?
On my project I'm using Groovy with Spring Data JPA's Specification's to construct Hibernate queries.
I can't provide my actual queries but to illustrate my problem let's say I have Building entities, and each Building has Floors and each Floor has both Rooms and Windows.
The behavior I'm attempting to simulate is something like this native SQL query:
SELECT b.*, r.*
FROM building b
INNER JOIN floor f ON b.id = f.building_id
INNER JOIN window w ON f.id = w.floor_id
LEFT OUTER JOIN room r ON f.id = r.floor_id
WHERE w.id = 1;
I have a specification similar to the below:
public class MySpec implements Specification<Building> {
#Override
public Predicate toPredicate(final Root<Building> root, final CriteriaQuery<?> query, final CriteriaBuilder cb) {
final Join floorsJoin = root.join("floors");
final Join windowsJoin = floorsJoin.join("windows");
//I'd like to remove this line
final Fetch floorsFetch = root.fetch("floors"); // <---
floorsFetch.fetch("rooms", JoinType.LEFT);
cb.equal(windowsJoin.get("id"), 1L);
}
}
The line annotated above is my issue. If I leave it, the generated query looks something like this:
SELECT b.*, f2.*, r.*
FROM building b
INNER JOIN floor f ON b.id = f.building_id
INNER JOIN window w ON f.id = w.floor_id
INNER JOIN floor f2 ON b.id = f2.building_id
LEFT OUTER JOIN room r ON f2.id = r.floor_id
WHERE w.id = 1;
(notice the duplicate INNER JOIN of floor and the unneeded f2.* data)
If I remove it, and use the floorsJoin instead to fetch rooms, I get the following Hibernate error:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
The unneeded f2.* data would be OK except I can't replace the above floorsJoin with the floorsFetch because I need to join with the windows table (without fetching windows) and the Fetch class doesn't have a .join method.
I'm having a difficult time figuring out how I would accomplish what I need while still generating a single query; surely I must be missing something simple.
Any thoughts or advice you could provide would be much appreciated.
Thanks a lot,
B.J.
Well it's not that simple with the JPA Criteria API. With Hibernate you could simply cast the Fetch to a Join I guess but that's not going to help you that much. I am not sure how you use the specification in this case, but if you could write the query as a whole it could look like the following
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Building> root = cq.from(Building.class);
final Join floorsJoin = root.join("floors");
final Join windowsJoin = floorsJoin.join("windows");
final Join roomsJoin = floorsJoin.join("rooms", JoinType.LEFT);
cb.equal(windowsJoin.get("id"), 1L);
cq.multiselect(
root,
roomsJoin
);
I have the following classes:
public class A{
private Set<B> bSet;
}
public class B{
private Set<C> cSet;
private boolean isAvailable;
}
public class C{}
The HQL is:
select a from A a
left join fetch a.bSet
left join fetch b.cSet
where a.id = ? and bSet.isAvailable = ?
The question is I can't use set in where clause. How can I process this query?
try this way I just gave alias to your queries part
select a from A a
left join fetch a.bSet b
left join fetch b.cSet c
where a.id = ? and b.isAvailable = ?
if that not work for you try toreplace ? with :id and :isAvilable Respectively as folows
select a from A a
left join fetch a.bSet b
left join fetch b.cSet c
where a.id = :id and b.isAvailable = :isAvailable
most likely one of the two must work for you.
I have a scenario where I need to load all the child values in one case and some specific child values in other . I am using a single bean for both the cases and writing the queries using named query.
#namedqueries{
#namedQuery(name="query1") = "select parent from Parent parent",
#namedQuery(name="query2") = "select parent from Parent parent",
}
Class Parent {
#manytomany
#join mentioned my join condition here //
List<Child> child ;
}
Class Child
{
String A;
String B;
String C;
#manytomany(mappedby = "child")
List<parent> parent ;
}
Now in my query 2 I need to load only String A not String B and String C .
I tried using
"select parent.child .A from Parent parent" as Query 2
but getting the below error
"Attempting to navigate to relation field via multi-valued association and
jpql doesnt allow traversal through multi valued relationship. Try join instead"
So any suggestions on how to proceed on this ..
1) Should I have to create a new bean for each Query
2) Or Can we control the child object parameters in specific named queries
You are accessing a collection when you say select parent.child and you can't say select parent.child.A this is wrong according HQL standards. You need to do this using join as the error message is suggesting:
select c.A from parent as p join p.child as c
Then no, you don't have to create a new bean for each query.
I want to annotate following structure:
I have this query:
SELECT A.*, BES.*, BES_2.*
INNER JOIN BES ON A.a = BES.a AND A.b = BES.b
INNER JOIN BES AS BES_2 ON A.a = BES_2.a AND A.b = BES_2.b
WHERE (BES.c = N'foo') AND (BES_2.c = N'bar')
I have the entities Job (representing A) and JobEndPoint (representing BES). The Job object should contain two JobEndPoint which map like a one-to-one relation. I need two JOIN the table two times checking for the same values only differed by the column "c" which I check in the WHERE statement.
#OneToOne
private JobEndPoint from;
#OneToOne
private JobEndPoint to;
My problem is now that the database columns and the object fields differ a lot and I don't know how to add the WHERE statement.
Create a JPA repository, and type a custom #Query.
I assume you already linked the parent and JobEndPoint classes over a and b fields. (To do that, define a multiple-column id on JobEndPoint and specify joinColumns in the parent class.)
#Query("SELECT u FROM parent
LEFT JOIN u.from bes
LEFT JOIN u.to bes2
WHERE bes.c = 'foo'
AND bes2.c = 'bar'")
Set<Parent> findMatchingParents()