spring data jpa query select all rows if given parameter collection is null - spring-boot

I want to write a query that selects all rows by given type collection for my fileRepository(There are 3 types as "1", "2" and "3"), if that parameter is not given from frontend, then it should return all rows.
I am using a Repository with #RepositoryRestResource annotation to achieve this.
It works fine for single type query(not Collection)
#Query("SELECT t FROM #{#entityName} t WHERE :fileType IS NULL OR t.fileType = :fileType")
Page<MyFile> findByFileType(#Param("fileType") String fileType, #Param("page") Pageable pageable);
it returns all entities when I don't give any arguments i.e : "http://localhost:8080/api/myFiles/search/findByFileType"
and returns all Files which have type "1" when I search with 1 parameter:
"http://localhost:8080/api/myFiles/search/findByFileType?fileType=1"
But problem occurs when I try to write a query from collection of types and I tried this
#Query("SELECT t FROM #{#entityName} t WHERE :fileTypes IS NULL OR t.fileType IN :fileTypes")
Page<MyFile> findByFileType(#Param("fileTypes") Collection<String> fileTypes, #Param("page") Pageable pageable);
It still works for the example localhost links that I gave above but multiple parameter throws "java.sql.SQLSyntaxErrorException: ORA-00920: invalid relational operator" error with this link:
"http://localhost:8080/api/myFiles/search/findByFileType?fileType=1,2"
Edit: I am using Oracle11g as database.

Related

Spring JPA repository method to get sorted distinct and non-null values

To get distinct data based on multiple columns and exclude NULL values on a column and sort the result in SQL, I would write query like:
SELECT DISTINCT CAR_NUMBER, CAR_NAME
FROM CAR
WHERE CAR_NUMBER IS NOT NULL
ORDER BY CAR_NUMBER
This would return me rows with distinct values for CAR_NUMBER and CAR_NAME and it would exclude any rows having CAR_NUMBER = NULL and finally, it would sort the result by CAR_NUMBER.
However, In Spring JPA, I gather you can use either methods named based on your entity fields or using #Query annotation.
I am trying to do this:
List<Car> findDistinctByCarNumberAndCarNameAndCarNumberIsNotNull(Sort sort);
, and to call this method like:
myRepo.findDistinctByCarNumberAndCarNameAndCarNumberIsNotNull(Sort.by("carNumber"));
but this is failing on Maven > Install with error like "findDistinctByCarNumberAndCarNameAndCarNumberIsNotNull(Sort sort) expects at least 1 arguments but only found 0".
Similarly, I tried using #Query like below but with same effect:
#Query(SELECT DISTINCT c.carNumber, c.carName FROM carEntity c WHERE c.carNumber IS NOT NULL ORDER BY c.carNumber)
List<Car> findAllCars();
I figured out the problem. Following is how I solved it:
In my repository:
#Query("select distinct c.carNumber, c.carName from CarEntity c where c.carNumber is not null")
List<Object> findAllDistinctRegions(Sort sort);
Important here to realize is that #Query returns List<Object>, not List<Car>.
Next, in my service, call this method:
List<Object> carData = carRepository.findAllDistinctCars(Sort.by("carNumber"));
That worked finally fine; however, I run into another problem where I had to do necessary conversion from List to List.
// This is bit tricky as the returned List<Object> is actually
// List<Object[]>. Basically, each field returned by the #Query
// is placed into an array element.
//To solve it, I had to do following:
List<Car> cars = new ArrayList<Car>();
for(Object data: carsData) {
Object[] obj = (Object[]) data;
cars.add(new CarDto((Short) obj[0], ((String) obj[1]));
}
I just remembered there is a better way to solve this than that helper function that you described in your answer and thought I would share it.
Projection in JPQL would be a cleaner way to create your DTO:
#Query("SELECT DISTINCT new com.yourdomain.example.models.MyDto(c.carNumber, c.carName)
FROM CarEntity c WHERE c.carNumber is not null")
List<CarDto> findAllDistinctRegions(Sort sort);

Spring data jpa projection could not extract ResultSet

I'm trying to map my entity to projection using the below query but i'm getting error as
Exception : could not extract ResultSet SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
here is the query
#Query("select rf.rfqID as rfqID,rf.creationDate as creationDate," +
"rf.deadLineDate as deadLineDate,rf.details as details," +
"rf.message as message, rf.rfqDoc as rfqDoc," +
"CASE WHEN (rf.creationDate > CURRENT_DATE) THEN 'open' ELSE 'closed' END as status," +
"rf.rfqMembers as rfqMembers " +
"from RFQ rf where rf.createdBy = ?1")
Page<RfqDto> loadAllRfq(String creator, Pageable pageable);
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
here is my projection interface
public interface RfqDto {
String rfqID();
Date creationDate();
Date deadLineDate();
String details();
String message();
String rfqDoc();
String status();
List<RfqMember> rfqMembers();
}
The root cause of your problem is here:
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
As it's explained in the documentation:
The important bit here is that the properties defined here exactly match properties in the aggregate root.
...
The query execution engine creates proxy instances of that interface at runtime for each element returned and forwards calls to the exposed methods to the target object.
So, you can not use spring data jpa projection for your case. You can not use hibernate/jpa projection as well, because it dose not support collections in row results.
You can try to use Blaze-Persistence Entity Views. See for example this answer.

Problem rendering the result set columns names with interface projection method names - Fetching Multiple Columns from Multiple Tables

I need multiple columns from multiple tables data.
Using Native Query:
#Query(value = "select t1.name as name, t1.phone as phone, t2.address as address, t2.pincode as pincode
from tablet t1, table2 t2
where t1.id=t2.tab1_id", nativeQuery = true)
List<MultipleColumnValues> getMultipleColumnsFromMultipleTables();
The return type of the above Query is a List of below projection:
public interface MultipleColumnValues {
String getName();
String getPhone();
String getAddress();
String getPincode();
}
I am getting the List successfully.
But:
The results are storing in different variables like,
The column names in the query mentioned are not rendering properly with the projection method Names.
eg: column 'name'(db query) value is stored in getPincode(), and pincode(db Query) is stored in getAddress()
How to render/map the result set names with the exact projection method names correctly?
This is a bug in Spring Data JPA version that is used in Spring Boot 1.5.2.
You have to upgrade to 1.5.3 then everything will work.
That't link to the issue: https://jira.spring.io/browse/DATACMNS-927

Null and Empty Check for a IN Clause parameter for Spring data jpa #query?

My Spring data JPA code to get the data from db based on some search criteria is not working. My DB is SQL Server 2012, same query seem to work with MYSQL DB.
Code Example :
#Query(value = "select * from entity e where e.emp_id=:#{#mySearchCriteria.empId} and ((:#{#mySearchCriteria.deptIds} is null or :#{#mySearchCriteria.deptIds} ='') or e.dept_id in (:#{#mySearchCriteria.deptIds})) ", nativeQuery = true)
public List<Entity> search(#Param("mySearchCriteria") MySearchCriteria mySearchCriteria);
if list mySearchCriteria.deptIds has more than one value- it's not working(it's actually translating it to wrong query. Any lead? Thanks in advance.
Note: data type for deptIds is List of Integer
Its complaining because values of {#mySearchCriteria.deptIds} is comma separated list e.g. 'Value1', 'Value2' so the query gets translated as ('Value1', 'Value2' is null) which causes this error.
Need to verify if list is empty or not and then change the query with IN clause and one without IN clause.
Surround the list by parentheses. This works for me.
(:#{#mySearchCriteria.deptIds}) is null

SimpleJpaRepository Count Query

I've modified an existing RESTful/JDBC application i have to work with new features in Spring 4... specifically the JpaRepository. It will:
1) Retrieve a list of transactions for a specified date. This works fine
2) Retrieve a count of transactions by type for a specified date. This is not working as expected.
The queries are setup similarly, but the actual return types are very different.
I have POJOs for each query
My transactions JPA respository looks like:
public interface MyTransactionsRepository extends JpaRepository<MyTransactions, Long>
//My query works like a charm.
#Query( value = "SELECT * from ACTIVITI_TMP.BATCH_TABLE WHERE TO_CHAR(last_action, 'YYYY-MM-DD') = ?1", nativeQuery = true )
List< MyTransactions > findAllBy_ToChar_LastAction( String lastActionDateString );
This returns a list of MyTransactions objects as expected. Debugging, i see the returned object as ArrayList. Looking inside the elementData, I see that each object is, as expected, a MyTransactions object.
My second repository/query is where i'm having troubles.
public interface MyCountsRepository extends JpaRepository<MyCounts, Long>
#Query( value = "SELECT send_method, COUNT(*) AS counter FROM ACTIVITI_TMP.BATCH_TABLE WHERE TO_CHAR(last_action, 'YYYY-MM-DD') = ?1 GROUP BY send_method ORDER BY send_method", nativeQuery = true )
List<MyCounts> countBy_ToChar_LastAction( String lastActionDateString );
This DOES NOT return List as expected.
The object that holds the returned data was originally defined as List, but when I inspect this object in Eclipse, I see instead that it is holding an ArrayList. Drilling down to the elementData, each object is actually an Object[2]... NOT a MyCounts object.
I've modified the MyCountsRepository query as follows
ArrayList<Object[]> countBy_ToChar_LastAction( String lastActionDateString );
Then, inside my controller class, I create a MyCounts object for each element in List and then return List
This works, but... I don't understand why i have to go thru all this?
I can query a view as easily as a table.
Why doesn't JPA/Hibernate treat this as a simple 2 column table? send_method varchar(x) and count (int or long)
I know there are issues or nuances for how JPA treats queries with counts in them, but i've not seen anything like this referenced.
Many thanks for any help you can provide in clarifying this issue.
Anthony
That is the expected behaviour when you're doing a "group by". It will not map to a specific entity. Only way this might work is if you had a view in your database that summarized the data by send_method and you could map an entity to it.

Resources