The administrative locations in my country are organized in the following precedence order(largest to smallest):
Country > Region > District > Council > locality.
All entities are well established with one-to-many mapping between parents and children entities
I want to get the set of localities with their corresponding councils and Districts and Regions with the following named query;
#NamedQuery(name = "LocalityWithCouncilAndDistrictAndRegionByLocalityId",
query = "SELECT DISTINCT lc " +
"FROM Locality lc " +
"LEFT JOIN FETCH lc.council c " +
"LEFT JOIN FETCH c.district dst " +
"LEFT JOIN FETCH dst.region " +
"WHERE lc.localityId = :localityId")
But the validation fails with an error saying
JOIN FETCH expressions cannot be defined with an identification variable
The error highlights on these two lines below from the query;
"LEFT JOIN FETCH lc.council c " +
"LEFT JOIN FETCH c.district dst " +
Please kindly help me on the best approach to resolving this.
Related
I am trying to use this query in springboot so I can display the results in a webpage. I know that this query works because I tested it in postgresql and it gave me the right results.
But JPA is telling me that the '(' after the first FROM is an unexpected token and the query was therefore viewed as invalid.
This is my query:
#Query(
"SELECT com.example.imse22.model.TrvlA_Cust_Dto(books_query.name, count(travelA_query.customer_id)) " +
"FROM (SELECT DISTINCT customer_servant.employee_id, books.customer_id FROM customer_servant " +
"INNER JOIN books ON customer_servant.employee_id = books.customer_servant_id) AS travelA_query " +
"INNER JOIN " +
"(SELECT travel_agency.id, travel_agency.name, employee.employee_id FROM travel_agency " +
"INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) AS books_query " +
"ON travelA_query.employee_id = books_query.employee_id " +
"GROUOP BY travelA_query.name")
can somebody help me out how I could rewrite the query so that JPA approves it?
Your query is native so you should declare it in that way:
#Query(
value = "SELECT com.example.imse22.model.TrvlA_Cust_Dto(books_query.name, count(travelA_query.customer_id)) " +
"FROM (SELECT DISTINCT customer_servant.employee_id, books.customer_id FROM customer_servant " +
"INNER JOIN books ON customer_servant.employee_id = books.customer_servant_id) AS travelA_query " +
"INNER JOIN " +
"(SELECT travel_agency.id, travel_agency.name, employee.employee_id FROM travel_agency " +
"INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) AS books_query " +
"ON travelA_query.employee_id = books_query.employee_id " +
"GROUOP BY travelA_query.name", nativeQuery = true)
link point 2.2: https://www.baeldung.com/spring-data-jpa-query
Ok so this is how I solved it:
I changed my query into a native one just like #notAPPP pointed out and then I only had to add an alias for the LEFT JOIN (also I changed INNER JOIN to LEFT JOIN).
here the code example:
#Query(value = "SELECT combined.name as name, count(combined.customer_id) as id " +
"FROM (" +
"(SELECT travel_agency.name, travel_agency.id, employee.employee_id " +
"FROM travel_agency INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) as trvlEmp " +
"LEFT JOIN " +
"(SELECT books.customer_id, books.customer_servant_id, customer_servant.employee_id " +
"FROM books INNER JOIN customer_servant ON books.customer_servant_id = customer_servant.employee_id) as custBooks " +
"ON trvlEmp.employee_id = custBooks.employee_id) as combined " + // this "AS combined" got added
"GROUP BY combined.name", nativeQuery = true)
This makes sense, because after a FROM clause one should wirte the name of a table or a result table (e.g. from two joined queries like in my case). As I didnt specify an alias for the LEFT JOIN of my two subqueries, JPA obviously didnt know how to handle the result of those subqueries. Therefore always name your subqueries if they are not used in a WHERE clause, but rather with a FROM clause, like in my case. E.g. the name I gave my LEFT JOIN is "combined" as seen in the code example above.
Also I changed my INNER JOIN to a LEFT JOIN to get the value 0 of the elements that have 0 counts of what I wanted to count in the table.
If you want to know how to handle the result which such a query returns follow this link.thorben-janssen.com/spring-data-jpa-dto-native-queries
I have the following query with all of these join/fetches:
public interface InitiativeRepository extends JpaRepository<Initiative, Long> {
#Query("select distinct i from Initiative i " +
"left join fetch i.theme t " +
"left join fetch t.themeQuestions tq " +
"left join fetch tq.initiativeProfileQuestion ipq " +
"left join fetch ipq.answers " +
"left join fetch ipq.answerLogs al " +
"where al.revision = i.revision " +
"order by ipq.question asc")
public List<Initiative> getThemeAndQuestionsAndAnswerLogs();
}
Because I'm doing so many joins, obviously hibernate is fetching all attributes of each object. For example, left join fetch i.theme t fetches all attributes of theme. What if I only want to fetch the theme name and themeQuestions attribute within the theme object (I don't want any unnecessary ones)?
I'm not sure if this is doable through only an annotated query. Any ideas would be appreciated.
I'm trying to get the "Extracto" objects from the database where the difference in days between the current date and the final date of the Extracto object is less or equal 15, I didn't find useful information about this issue, is there a method in HQL or a manual calculation way to achieve this in the same query, without tampering the result set after the query is done??
here is my query:
String queryStr = "Select distinct E from Extracto E"
+ " left join fetch E.afiliados afiliado"
+ " left join fetch afiliado.personas personaAfiliado"
+ " left join fetch E.vehiculos vehiculo"
+ " left join fetch E.conductoresByIdConductor conductor1"
+ " left join fetch conductor1.personas persona1"
+ " left join fetch E.conductoresByIdConductor2 conductor2"
+ " left join fetch conductor2.personas persona2"
+ " left join fetch E.conductoresByIdConductor3 conductor3"
+ " left join fetch conductor3.personas persona3"
+ " left join fetch E.contrato contrato"
+ " left join fetch contrato.clientes cliente"
+ " left join fetch cliente.personas personaCliente"
+ " where E.servicio is null and"
+ " (E.fechaFinal - :fechaActual)<=15"
+ " and E.fechaFinal>:fechaActual)";
where E.servicio is null and
E.fechaFinal <= :fechaMax
and E.fechaFinal>:fechaActual
Then provide fetchaMax parameter value as fechaActual + 15 days.
this is my namedquery:
#NamedQuery(
name = "User.findOneWithLists",
query = "SELECT u FROM User u "
+ "LEFT JOIN FETCH u.aTemplates "
+ "LEFT JOIN FETCH u.bTemplates "
+ "LEFT JOIN FETCH u.bp "
+ "LEFT JOIN FETCH u.aCredentials "
+ "LEFT JOIN FETCH u.st WHERE (st.deleted = false) "
+ "LEFT JOIN FETCH u.bCredentials "
+ "LEFT JOIN FETCH u.cl "
+ "WHERE u.id= :id")
My problem is that I get an error when the application starting:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: LEFT ....
On the st side there is an annotation
#ManyToOne
#JoinColumn(name = "st_user")
private User user;
Any idea how can I handle this where clause?
Check a SQL syntax, you can't use left join after where clause. If you are looking at the SQL generated form that named query you will see that joined tables in the query the where clause comes after joins and should specify equal condition that links those tables by the keys. The primary key of the main table on the left and the foreign key of the joined table on the right. The joined table is specified by the property of your many-to-one association.
#NamedQuery(
name = "findOneWithLists",
query = "from Table t left join User u where u.id= :id"
)
For join conditions Hibernate provides the with keyword, even before JPA 2.1.
The relevant part of your query thus would look like this:
SELECT u FROM User u ... LEFT JOIN u.st WITH st.deleted = false
I'm not sure about LEFT JOIN FETCH u.cl with u.id= :id but if I remember correctly, that's not as easy and might have to be resolved with an adapted join and u.ui = :id in the where condition.
LEFT JOIN FETCH u.st WITH st.deleted = false`
This is not supported, since you can't do a partial fetch.
Left outer join is supposed to get all data from left table no matter if there is matching record from B table, however if left tables right_id column is null, records cant be got.
I am explaining more
In Data model: Order.java, it is my LEFT table, there is a one to one relation
#OneToOne(targetEntity = OrderShippingDetail.class, optional=true, cascade = {CascadeType.ALL})
#JoinColumn(name = "SHIPPING_DETAIL_ID", referencedColumnName = "ID")
private OrderShippingDetail shippingDetail;
and HQL is:
hql = "SELECT " +
"o.id as id, " +
"o.createTime as createTime, " +
"o.customerEmailAddress as customerEmailAddress, " +
"o.customerPhoneNumber as customerPhoneNumber, " +
"o.customerNote as customerNote, " +
"o.invoicePrintedFlag as invoicePrintedFlag, " +
"shippingAddress.address.personName as shippingPersonName, " +
"shippingDetail.shippingCompany.id as shippingCompanyId, "+
"shippingDetail.shippingCompany.name as shippingCompanyName, "+
"shippingDetail.receiptNumber as shippingReceiptNumber, "+
"shippingDetail.trackingNumber as shippingTrackingNumber, "+
"shippingDetail.price as shippingPrice, "+
"o.invoiceNumber as invoiceNumber " +
"FROM Order AS o " +
"LEFT OUTER JOIN o.shippingAddress AS shippingAddress " +
"LEFT OUTER JOIN o.shippingDetail AS shippingDetail ";
But there comes just records which "SHIPPING_DETAIL_ID" is NOT null. Is there an error with HQL? It is created by modelling SQL command which is automatically created when hibernate runs.
I found this,
HQL supports two forms of association joining: implicit and explicit.
The queries shown in the previous section all use the explicit form,
that is, where the join keyword is explicitly used in the from clause.
This is the recommended form.
The implicit form does not use the join keyword. Instead, the
associations are "dereferenced" using dot-notation. implicit joins can
appear in any of the HQL clauses. implicit join result in inner joins
in the resulting SQL statement.
And I remove my dot notation in the SELECT part, so my new HQL:
hql = "SELECT " +
"o.id as id, " +
"o.createTime as createTime, " +
"o.customerEmailAddress as customerEmailAddress, " +
"o.customerPhoneNumber as customerPhoneNumber, " +
"o.customerNote as customerNote, " +
"o.invoicePrintedFlag as invoicePrintedFlag, " +
"shippingDetail, " +
"o.invoiceNumber as invoiceNumber " +
"FROM Order AS o " +
"LEFT OUTER JOIN o.shippingAddress AS shippingAddress " +
"LEFT OUTER JOIN o.shippingDetail AS shippingDetail ";
So, it works, it returns all records in Order table, however, I dont want to select all columns and relations in the ShippingDetail object. What can I do to solve this issue?
Add another explicit left join to the query:
SELECT o.id as id,
...,
shippingCompany.id as shippingCompanyId,
shippingCompany.name as shippingCompanyName,
...
FROM Order AS o
LEFT OUTER JOIN o.shippingAddress AS shippingAddress
LEFT OUTER JOIN o.shippingDetail AS shippingDetail
LEFT OUTER JOIN shippingDetail.shippingCompany AS shippingCompany