How to pass Byte value to JPQL in Spring? - spring

I have an Interface wich
extends JpaRepository
I have method in it:
#Query("SELECT a FROM ArticlesEntity a " +
"WHERE ((:approved = 2 ) or (a.approved = :approved)) ")
Page<ArticlesEntity> filterByAllPage(
#Param("approved") Byte approved,
Pageable pageable);
When this method is invoked I have an exeption:
java.lang.IllegalArgumentException: Parameter value [2] did not match expected type [java.lang.Integer (n/a)]
When I change
(:approved = 2 )
to
(:approved is null)
or
#Param("approved") Byte approved
to
#Param("approved") Integer approved
or
"WHERE ((:approved = 2 ) or (a.approved = :approved))"
to
"WHERE (a.approved = :approved) "
it works.
It seems that should be something like
(:approved = (byte) 2 )
or
(:approved=2.byteValue())
but both didn't work also.
Is there any way to use Byte here or it's better to switch to Integer ?
The database is MySQL and it has table "articles" with column "approved" of "TINYINT(1)" type.

Related

How to add optional parameter in JPQL?

How to use/add optional parameter in JPQL?
#Query(value = "SELECT stud FROM Student stud where stud.name = :studentName AND stud.age IN :studentAgeList")
List<Student> getStudents(
#Param("studentName ") String studentName,
#Param("studentAgeList") List<Integer> studentAgeList
)
How to make studentAgeList parameter in above query ?
I tried below :
#Query(value = "SELECT stud FROM Student stud where stud.name = :studentName AND (:studentAgeList IS NULL OR stud.age IN :studentAgeList))
List<Student> getStudents(
#Param("studentName ") String studentName,
#Param("studentAgeList") List<Integer> studentAgeList
)
But getting error : unexpected AST node:
Tried above but getting error
JPQL does not support optional parameters, you can use overload methods with different queries or criteria API or JPA specifications.
may be get answer here: Set optional parameters in JPQL Query

How to set MyBatis Spring replace null values with text NULL in SQL statements?

I check existsing of row like this.
#Select("SELECT id FROM ${table_path} " +
"WHERE id = ${cluster_id} AND " +
"id_second = ${node_id} AND " +
"resource_type_id = ${resource_type_id}")
BillingData isRecordExist(#Param("table_path") String tablePath,
#Param("cluster_id") Integer clusterId,
#Param("node_id") Integer nodeId,
#Param("resource_type_id") Integer resourceTypeId);
But sometimes there is no resource_type_id and I get statements like this:
"SELECT id FROM tablename WHERE id = 1 AND id_second = 2 AND resource_type_id = "
It's not valid and my app crashes. How can i set up batis to replace null value params with NULL text?
I tried search on internet. Settings param 'jdbcTypeForNull' doesn't affect. Type converters can't help me too

How to check the length of a JPA query parameter if it is a list?

#Query("Select DISTINCT answer from Answer answer " +
"WHERE ( answer.user = :user or (:user is null)) " +
"AND ( answer.quiz in :quizzes or (:quizzes is null))"
)
public Page<Answer> multiParam(Quiz[] quizzes, User user, Pageable pageable);
This query works as long as quizzes is provided.
User however is optional.
The problem is that when quizzes the parameter is missing, the is null check will fail with this error:
org.springframework.dao.InvalidDataAccessApiUsageException: Encountered array-valued parameter binding, but was expecting [com.quiz.models.Quiz (n/a)]; nested exception is java.lang.IllegalArgumentException: Encountered array-valued parameter binding, but was expecting [com.quiz.models.Quiz (n/a)
I want to find a way to make Quizzes the parameter as optional.
Try the following :
#Query("Select DISTINCT answer from Answer answer " +
"WHERE ( answer.user = :user or (:user is null)) " +
"AND (COALASCE(:quizzes,null) IS NULL OR answer.quiz in :quizzes))"
public Page<Answer> multiParam(List<Quiz> quizzes, User user, Pageable pageable);
COALASCE returns the first non null value , which in this case would return null when quizzes is null.
Not sure if this would work with Array type or not.
A native solution from JPA is still pending : https://github.com/spring-projects/spring-data-jpa/issues/622

Spring Data - Custom DTO Query with filtering

I have a complexe application and I need to retrieve and filter 1000~5000 object for an xls export. Each object having multiple eager relationship (I need them for the export).
If I retrieve all the objects and their relationship as it is, I got some stackoverflow error.
Generaly when I need to make a big export, in order to make it efficient I use a DTO object with an #Query like this :
public interface myRepository extends JpaRepository<Car, Long> {
#Query("SELECT new com.blabla.myCustomObject(p.name, p.surname, c.model, c.number ...) "
+ "FROM Car c "
+ "LEFT JOIN c.person p "
+ "WHERE ... ")
List<myCustomObject> getExportCustomObject();
}
The problem is that the #Query is static and I want to add dynamic filter to my Query (Specifications, Criteria or some other system...)
How to do it ?
Specification cannot be used because this is only the where clause.
But you can use Criteria API. Here's an example. The BasicTeacherInfo is the DTO:
CriteriaQuery<BasicTeacherInfo> query = cb.createQuery(BasicTeacherInfo.class);
Root<Teacher> teacher = query.from(Teacher.class);
query.multiselect(teacher.get("firstName"),teacher.get("lastName"));
List<BasicTeacherInfo> results = em.createQuery(query).getResultList();
You can use #Param annotation to pass dynamic values to HQL, something like:
#Query("SELECT new com.blabla.myCustomObject(p.name, p.surname, c.model, c.number ...) "
+ "FROM Car c "
+ "LEFT JOIN c.person p "
+ "WHERE c.status = :status AND p.name = :name")
List<myCustomObject> getExportCustomObject(
#Param("status") Integer status,
#Param("name") String name
);
Below is one of the possible way where you can try to add offset and limit into your query you can make it dynamic with the help off placeholders.
Below is an sample pseudo code for reference:
Dao Layer:
#Query(value="SELECT e FROM tablename e WHERE condition_here ORDER BY e.id offset :offset limit:limit ")
public returnType yourMethod(String name, int offset, int limit);
Service Layer:
long count = number of records in db.
int a = // number of records to be fetched on each iterations
int num_iterations = count % a ;
int additionalrecords = count / a;
int start= 0;
while(num_iterations>0)
{
dao.yourMethod(start,a);
start = start+a;
count--;
// write your data to excel here
}
dao.yourMethod(start,additionalrecords);
Hope it is helpful.

How to use oracle NVL function in spring data repository nativeQuery

I am trying to use oracle' NVL function in nativeQuery of Spring Data Repository.
While i am passing null value in programId parameter then it is throwing exception (ORA-00932: inconsistent datatypes: expected NUMBER got BINARY) and if i am passing a valid value in "programId" then it is working properly.
public interface ProgramRulesRepository
{
public static final String FIND_PROGRAM_RULES_BY_PARTICIPANT_ID_AND_ROLE_OR_PROGRAM = " SELECT DISTINCT pr.id , pr.program_id , prgm.display_name , pr.group_id , pr.type , pr.cmmo_key FROM program prgm , program_rule pr , program_audience pa , participant_audience paa WHERE prgm.id = pa.program_id AND pr.program_id = pa.program_id AND pa.audience_id = paa.audience_id AND pr.type = :roleType AND paa.participant_id = :participantId "
+ " AND pr.program_id = NVL ( :programId ,pr.program_id )";
#Query( value = FIND_PROGRAM_RULES_BY_PARTICIPANT_ID_AND_ROLE_OR_PROGRAM, nativeQuery = true )
List<Object[]> findByParticipantIdAndRoleTypeOrProgramId( #Param( "participantId" ) Long participantId, #Param( "roleType" ) String roleType, #Param( "programId" ) Long programId );
}
Exception :
Caused by: java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
Avoid NVL and COALESCE when using Hibernate. COALESCE function needs to have all parameters of the same type. NVL is using implicit casting which doesn't work well when there is BINARY or VARBINARY. And where this BINARY came from? Well, Hibernate is setting NULL value as type of BINARY and ignores the real datatype backed by Java. When you set logging level to trace you can see in output:
binding parameter [1] as [VARBINARY] - [null]
So when the other type of in COALESCE or NVL function is for example NUMBER, you will get that error ORA-00932.
A good solution for this problem is this:
" AND (:programId IS NULL OR pr.program_id = :programId)"
Doing this way, if your param is null this sentence will result TRUE and won't discard the register, and if it is not null will be compared with the value stored in its field.
I have faced this problem with MongoDB. But I could solve this problem by using mongoTemplate as like,
Query query = new Query();
Criteria criteria = new Criteria();
List<Criteria> orCriterias = new ArrayList<>();
if( dto.getId() != null) {
orCriterias.add(Criteria.where("id").is(Integer.parseInt(dto.getId())));
}
... so on for other fields
criteria.orOperator(orCriterias.toArray(new Criteria[orCriterias.size()]));
query.addCriteria(criteria);
List<StudentDTO> recordsList = mongoTemplate.find(query, StudentDTO.class,
"student_collection");

Resources