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)
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
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.
I have an entity class with many named queries with INNER JOIN<> ON <> sentence on it, when I try to execute a test using JUnit and in memory H2 database I get this exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join!
The query work fine, but it seems that H2Dialect dont support Inner Join this way, only like this:
INNER JOIN c.persona p
This is my NamedQuery:
#NamedQuery(name = "name", query = "SElECT NEW MyObject(p.firstName, "
+ "p.lastName, , tp.otherName, p.id, s.description, en.name, et.name , et.number, e.firstName, "
+ "e.lastName, e.street, e.date ) "
+ "FROM TypeC c INNER JOIN c.typeP p " + "INNER JOIN TypeTP tp ON tp.code = p.codeTP "
+ "INNER JOIN TypeS s ON s.code = c.codeS "
+ "INNER JOIN TypeEt et ON et.code = c.codeET "
+ "INNER JOIN TypeEN en ON en.code = c.codeEN "
+ "INNER JOIN TypeI i ON i.code = c.codeI " + "INNER JOIN i.typeE e "
+ "WHERE c.number = :NUMBER " + "AND e.code = :CODE ")
I'm using JPA.
Could anyone help me?
Thanks in advance.
Try JOIN instead INNER JOIN, JOIN means inner join by default.
Change H2 dialect to another if it possible.
I already found whats went wrong. TypeS, TypeET and TypeEN needed to be included in the persistence.xml file into the tag "persistence-unit" as
<class>co.com.myproject.persistence.entity.TypeS </class>
<class>co.com.myproject.persistence.entity.TypeET </class>
<class>co.com.myproject.persistence.entity.TypeEN </class>
and put the necesary SQL code for create and populate the tables in the create.sql and data.sql files used to generate the in memory h2 database.
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'm currently having an issue using Java JPA with EclipseLink - this query:
SELECT VAR_INPUT.*
FROM VAR_INPUT
INNER JOIN TYPE_VAR_INPUT
ON VAR_INPUT.ID_TYPE_VAR_INPUT = TYPE_VAR_INPUT.ID_TYPE_VAR_INPUT
WHERE TYPE_VAR_INPUT.IS_MANDATORY_TYPE_VAR_INPUT=true;
is working fine when run directly on my database, but doesn't work when I use it with JPA.
JPA Query:
#NamedQuery(name = "VarInput.findAVarInputllOfMandatoryType",
query = "SELECT v "
+ "FROM VarInput v "
+ "INNER JOIN TypeVarInput t "
+ "ON v.ID_TYPE_VAR_INPUT = t.ID_TYPE_VAR_INPUT "
+ "WHERE t.isMandatoryTypeVarInput=:isMandatoryTypeVarInput"),
When I execute it in my Java application, I get the following error:
"The field [VAR_INPUT.ID_VAR_INPUT] in this expression has an invalid table in this context."
Exception in thread "AWT-EventQueue-0" Local Exception Stack:
Exception [EclipseLink-6069] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: The field [VAR_INPUT.ID_VAR_INPUT] in this expression has an invalid table in this context.
Query: ReadAllQuery(name="VarInput.findAVarInputllOfMandatoryType" referenceClass=VarInput jpql="SELECT v FROM VarInput v INNER JOIN TypeVarInput t ON v.ID_TYPE_VAR_INPUT = t.ID_TYPE_VAR_INPUT WHERE t.isMandatoryTypeVarInput=:isMandatoryTypeVarInput")
at org.eclipse.persistence.exceptions.QueryException.invalidTableForFieldInExpression(QueryException.java:749) at org.eclipse.persistence.exceptions.QueryException.invalidTableForFieldInExpression(QueryException.java:749)
at org.eclipse.persistence.internal.expressions.FieldExpression.validateNode(FieldExpression.java:296)
My tables looks like that:
Table VAR_INPUT(ID_VAR_INPUT, NAME_VAR_INPUT, ID_TYPE_VAR_INPUT)
Table TYPE_VAR_INPUT(ID_TYPE_VAR_INPUT, NAME_TYPE_VAR_INPUT, IS_MANDATORY_VAR_INPUT)
"VAR_INPUT ManyToOne TYPE_VAR_INPUT"
Do you have any idea of why this happens?
NB: The Entities were generated by NetBeans
You don't use inner join in JQPL like that, you join on entity fields. I'm guessing now since you didn't provide entity code, but try this
#NamedQuery(name = "VarInput.findAVarInputllOfMandatoryType",
query = "SELECT v "
+ "FROM VarInput v "
+ "join v.type t "
+ "WHERE t.isMandatoryTypeVarInput=:isMandatoryTypeVarInput")
In this case you don't even need to join, you can simplify the query to this (inner join is implicitly used)
#NamedQuery(name = "VarInput.findAVarInputllOfMandatoryType",
query = "SELECT v "
+ "FROM VarInput v "
+ "WHERE v.type.isMandatoryTypeVarInput=:isMandatoryTypeVarInput")