#DataJpaTest does not throw excepted org.hibernate.exception.SQLGrammarException: - spring

I am using #DataJpaTest for testing my repository.
#Query(
"SELECT AVG(a.rating) as averageValue a.id as someId FROM SomeTable as a where someTable.id = :id")
SomReturnObject getExampleTable(#Param(value = "id") String dcsPoolIdPram);
The query should not work without group by but even though it should fail it does not.
I am using H2 in-memory database. The query fails when I run the app with the Postgres database.
I am using the following configuration.
jpa:
properties:
hibernate:
default_schema:
show_sql: true
jdbc.lob.non_contextual_creation: true
hibernate:
ddl-auto: create-drop
database-platform: org.hibernate.dialect.H2Dialect
security:
enabled: false
This gives an error when we run the application not when testing. Is this a bug of springData ? or am I doing something wrong ?

#Query(
"SELECT AVG(a.rating) as averageValue a.id as someId FROM SomeTable as a where someTable.id = :id")
SomReturnObject getExampleTable(#Param(value = "id") String dcsPoolIdPram);
This is not a native query. GroupBy is nessesary only when you use a native SQL query like in the following configuration.
#Query("SELECT AVG(a.rating) as averageValue a.id as someId FROM SomeTable as a where someTable.id = :id", nativeQuery = true)
Otherwise without using native, AVG is just a JPA function which should be provided by the ORM vendor and should be supported for your database.
Take a look here on HQL/JPQL aggregate functions provided by hibernate which is the default ORM vendor in spring data jpa.
As you can see in HQL/JPQL, the aggregate function can be used with groupBy or without, and is not the same as SQL language. In case that is used without a groupBy it just applies the aggregate function on the returned results from the HQL/JPQL query.

Related

How can I rewrite the a query containing a filter on a JSONB column using spring specifications

How can I rewrite the following query using Spring Specifications.
#Query(value = "SELECT * FROM product WHERE attributes #> CAST(:jsonObject AS JSONB)", nativeQuery = true)

Spring Data JPA - how to filter returned data based on a fields values?

I am trying to figure out how do I filter what data is being returned to me in Spring JPA.
I know that with Spring JDBC, I get full controll and I can basically write a query like:
SELECT * FROM CAR
WHERE ACCIDENT_DATE IS NULL
OR BUY_DATE >= CURRENT_DATE
ORDER BY CAR_NUMBER
But, with Spring JPA, we dont write queries, instead we write entities like
#Entity
#Table(name = "CAR", schema = "MY_SCHEMA")
public class Car {
#Id
public Long carNumber;
...
}
What is the way to filter which Cars are returned based on weather the
ACCIDENT_DATE is NULL and
BUY_DATE is greater than CURRENT_DATE
, ordered by CAR_NUMBER in Spring JPA?
With the help of #DirkDayne, figured out how to do this. Thank you Dirk
#Query("select c from CarEntity c where c.accidentDate is null or c.buyDate >= CURRENT_DATE")
List<CarEntity> getAllAvailableCars(Sort sort);
, then call it in service as:
List<CarEntity> cars= (List<CarEntity>) carRepository.getAllAvailableCars(Sort.by("carNumber"));

JPA nativeQuery with UNION does not support pagination

Consider the following tables:
TABLE A
id
sys_time
user_id
rent_time
TABLE B
id
sys_time
occur_time
I would like to use a UNION query in MYSQL to have this table and put data from both tables row by row with sys_time order:
TABLE AB
id
sys_time
user_id
occur_time
rent_time
I use the following query:
select id, sys_time, user_id, null as occur_time, rent_time from open_close
union
select id, sys_time, null as user_id, occur_time, null as rent_time from periodic
order by sys_time desc;
Now I define an #Entity with the following structure:
...
#Data
#Entity
#NamedNativeQuery(
name="TotalEntity.getTotal"
, query="select id, sys_time, user_id, null as occur_time, rent_time from open_close\r\n"
+ "union\r\n"
+ "select id, sys_time, null as user_id, occur_time, null as rent_time from periodic \r\n" + "order by sys_time desc;"
, resultClass=TotalEntity.class
)
...
// Entity Fields and so on
and the corresponding Repository:
#Repository
public interface TotalRepository extends JpaRepository<TotalEntity, BigInteger> {
#Query(nativeQuery = true)
public List<TotalEntity> getTotal();
}
Everything is OK up to now.
Now I want to add pagination:
#Repository
public interface TotalRepository extends JpaRepository<TotalEntity, BigInteger> {
#Query(nativeQuery = true)
public Page<TotalEntity> getTotal(Pageable page);
}
and use this:
...
private TotalRepository tr;
...
Pageable pageable = PageRequest.of(page, size,
direction.toUpperCase().equals("ASC") ? Sort.by(sort).ascending() : Sort.by(sort).descending());
Optional<Page<TotalEntity>> pe = Optional.ofNullable(tr.getTotal(pageable));
The following exception is thrown:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 20' at line 4
It seems that Hibernate can not modify the nativeQuery to add pagination statements. And I know that JPQL and JPA does not supprt UNIONs. Is there any workaround for this?
A workaround would be to introduce a view in the database layer with the union clause, and then execute the query upon the view.
This way, you can hide the union from JPA layer and queries can be executed using pageable as usual.
CREATE VIEW view_name AS
select id, sys_time, user_id, null as occur_time, rent_time from open_close
union
select id, sys_time, null as user_id, occur_time, null as rent_time from periodic
And modify the JpaRepository to query upon the view using prefered way, like native queries, column projections etc.
If you are not planning to use other functionalities from Pageable interface like getting the total records count, number of current slice etc., then try using offset and limit keywords in the query directly for the pagination.
Note : offeset corresponds to page and limit corresponds to size of content in the page

Named native query mapping in orm.xml

I am very new to Hibernate. I am trying to externalize basic SQL query to orm.xml
My query
SELECT CURRENT_TIMESTAMP FROM DUAL
I have tried following :
<named-native-query
name="JobTrackerEntity.getCurrentTimestamp"
result-class="java.sql.Timestamp">
<query>
SELECT CURRENT_TIMESTAMP FROM DUAL
</query>
</named-native-query>
But I get following error:
org.hibernate.MappingException: Unknown entity: java.sql.Timestamp
Please let me know how can I write the query in orm.xml. Also if I can refer any resources to get better understanding.
Update:
I have added a method in repository interface as follows:
#Repository
public interface TrackerRepository extends JpaRepository<TrackerEntity, TrackerId> {
#Query(nativeQuery=true)
Timestamp getCurrentTimestamp();
}
I'm calling getCurrentTimestamp() to execute query.
You must remove result-class="java.sql.Timestamp" because the result-class property must be an Entity.
edit:
CURRENT_TIMESTAMP results in a missing mapping in Hibernate dialect. You must provide your own dialect or if you don't need the timezone you better use:
SELECT LOCALTIMESTAMP FROM DUAL

How to use Customize your Queries in JPA with Query Methods (spring boot)

I want to retrieve a specific value from the database based on a criteria without using the query method in Spring JPA.
they query desired is
SELECT TOP 1 * FROM Co2 WHERE Co2.room = ?1 order by co2.id desc
which can be used in a normal native query annotation like so:
public interface Co2Respository extends CrudRepository<Co2, Integer> {
#Query("SELECT TOP 1 * FROM Co2 WHERE Co2.room = ?1 order by co2.id desc",
nativeQuery = true)
Co2 findLastInsertedValueForRoom(int id);
}
the question is how to achieve the same using the custom query method in Spring JPA
I will answer my own question,
the equivalent custom method for the query mentioned above is:
Co2 findTopByRoomOrderByIdDesc(Room room);

Resources