in code like this
#Query("select se.id from someEntity se"
+ " inner join se.anotherOne ao"
+ " inner join se.lazyOne l"
+ " where l.someField = true")
Should I use "fetch" to get someFiled from lazy entity or Hibernate/Jpa/Spring Data/God will do it for me?
It is not necessary as you pose the query, you could do the following:
#Query("select se.id, ao.id, l.id from someEntity se"
+ " inner join se.anotherOne ao"
+ " inner join se.lazyOne l"
+ " where l.someField = true")
And indicate as the class returned when executing the query a pojo with a constructor that matches in order and type with the parameters of the select clause as follows:
public YourPojo(Long idSomeEntity, Long idAnotherOne, Long idLazyOne){
//Object construction
}
The use of fetch would be for example if you wanted to bring you a list of someEntity entities with their lazyOne property fed
#Query("select se from someEntity se"
+ " join fetch se.anotherOne ao"
+ " join fetch se.lazyOne l"
+ " where l.someField = true")
That depends. If you JOIN FETCH lazy field, hibernate won't run another query to fetch it later. Otherwise when accessing this field, hibernate will have to query database for it. It's more of optimization thing.
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
Currently I have such piece of code, which doesn't work, since I have to add schema name before each table in a query(like DEV.DASHBOARDS_METADATA):
public interface DashboardMetadataDao extends CrudRepository<DashboardMetadata, Integer> {
#Query("SELECT D FROM DASHBOARDS_METADATA D " +
"INNER JOIN FAC_DASHBOARDS_LINK DL ON D.ID = DL.DASHBOARD_ID " +
"INNER JOIN FIRMS F ON DL.FAC_ID = F.FAC_UNIT_ID " +
"INNER JOIN USERS U ON U.FIRM_ID = F.FIRM_ID WHERE LOWER(U.USERID) = LOWER(:userid)")
public Set<DashboardMetadata> findByUserId(#Param("userid") String userId);
}
The problem is that schema name differs from database to database (DEV/QA/PROD). Normally I use component's method which prepend schema's name to each table during query generation. How can do this using annotations?
Thanks!
Hibernate has a variable that can be used in native queries to get schema name called: {h-schema}
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/query/native/Native.html#sql-global-catalog-schema You can just put {h-schema}table in your query. I think you have to convert it to a native query.
Below Code Snippet worked for me
#Query(
value = "select *\n" +
"from {h-schema}TABLE-A r left join {h-schema}TABLE-B p on r.ID=p.ID\n" +
"left join {h-schema}TABLE-C pe on p.ID=pe.ID\n" +
"left join {h-schema}TABLE-D e on pe.ENT_ID=e.ENT_ID\n" +
"where r.role_type='Provisioning'",
nativeQuery = true)
Currently I have such piece of code, which doesn't work, since I have to add schema name before each table in a query(like DEV.DASHBOARDS_METADATA):
public interface DashboardMetadataDao extends CrudRepository<DashboardMetadata, Integer> {
#Query("SELECT D FROM DASHBOARDS_METADATA D " +
"INNER JOIN FAC_DASHBOARDS_LINK DL ON D.ID = DL.DASHBOARD_ID " +
"INNER JOIN FIRMS F ON DL.FAC_ID = F.FAC_UNIT_ID " +
"INNER JOIN USERS U ON U.FIRM_ID = F.FIRM_ID WHERE LOWER(U.USERID) = LOWER(:userid)")
public Set<DashboardMetadata> findByUserId(#Param("userid") String userId);
}
The problem is that schema name differs from database to database (DEV/QA/PROD). Normally I use component's method which prepend schema's name to each table during query generation. How can do this using annotations?
Thanks!
Hibernate has a variable that can be used in native queries to get schema name called: {h-schema}
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/query/native/Native.html#sql-global-catalog-schema You can just put {h-schema}table in your query. I think you have to convert it to a native query.
Below Code Snippet worked for me
#Query(
value = "select *\n" +
"from {h-schema}TABLE-A r left join {h-schema}TABLE-B p on r.ID=p.ID\n" +
"left join {h-schema}TABLE-C pe on p.ID=pe.ID\n" +
"left join {h-schema}TABLE-D e on pe.ENT_ID=e.ENT_ID\n" +
"where r.role_type='Provisioning'",
nativeQuery = true)
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.
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