Using named parameters for method when I use #Query - java

I am using spring-data-jpa, I want update something, I have annotated my method in PaySupplierSettleBillRepository as
public interface PaySupplierSettleBillRepository extends JpaRepository<PaySupplierSettleBillEntity, Long>,
JpaSpecificationExecutor<PaySupplierSettleBillEntity> {
#Modifying
#Query("update PaySupplierSettleBillEntity p set p.payTime=:payTime,p.paymentOrder=:paymentOrder, p.transferTime=:transferTime, p.transferBank=:transferBank, p.transferOrder=:transferOrder, p.operatorName=:operatorName, p.remark=:remark where p.orderNumber=:orderNumber")
int updatePayInfo(PaySupplierSettleBillEntity entity);
}
I am getting following exception while starting
Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract xxxxxx
how I fix it ? thinks.

That is not how you write a #Query with named parameters. Take a look at the example from Spring documentation here (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.named-parameters).
If you want to provide an object as param, you can do something like this.
#Query("UPDATE Entity E SET E.name = :#{#entity.name}")
public void updateEntity(#Param("entity") Entity entity);

Caused by: java.lang.IllegalStateException: Using named parameters for method can be thrown when a method has redundant parameter which is not used in the #Query.
In your case, entity should be used in the SQL query like it's mentioned in the previous answer https://stackoverflow.com/a/56053250/5962766 or you should replace it with specifying necessary parameters one by one in the method signature.
Related: IllegalStateException with naming parameters in tomcat

Related

CRUD-Repository OrderBy does not expect parameter

I have this method defined in a CRUD-Repository :
List<MenuPriceByDay> findAllOrderByUpdateDate();
but when I init the app. I got this error:
Failed to create query for method public abstract java.util.List
com.tdk.backend.persistence.repositories.MenuPriceByDayRepository.findAllOrderByUpdateDate()!
No parameter available for part updateDate SIMPLE_PROPERTY (1): [Is,
Equals] NEVER.
Please can you check this spring jpa documentation ?
It must be like that
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
You can apply static ordering by appending an OrderBy clause to the
query method that references a property and by providing a sorting
direction (Asc or Desc).

JPA Repository and constructor with varargs

It is possible to use constructor of varargs in #Query (org.springframework.data.jpa.repository). What I mean is class like this:
public class EntityDTO {
public EntityDTO(Long id, LocalDate... dates) {
// some code here where dates
//which are converted to List<Pair<LocalDate, LocalDate> datesList
}
}
public interface CustomRepository extends JpaRepository<Entity, Long> {
#Query("SELECT new package.path.EntityDTO(id, date1, date2, date2) FROM Entity")
List<EntityDTO> findEntityList();
}
Now there is an error like this:
Unsatisfied dependency expressed through constructor parameter 3
Validation failed for query for method public abstract java.util.List CustomRepository.findEntityList(java.lang.Long,java.time.LocalDate,java.time.LocalDate)
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException:
Unable to locate appropriate constructor on class [EntityDTO]. Expected arguments are: long, java.time.LocalDate, java.time.LocalDate, java.time.LocalDate, java.time.LocalDate
It is only query example because dto can have id and LocalDate parameter from 2 to 12-14 in constructor, dates can be from different tables (entities). It depends from query. I want class more generic for this purpose. Query is much more complicated than in this example but I'm interested in some kind of constructor which give me possibility to create something similar that I described in EntityDTO constructor in comment. It is possible to use varargs in #Query?
Edit:
Do you have any suggestion what could I use if JPQL don't have this functionality?
I'm afraid that's impossible.
The way Hibernate implements matching constructor resolution, only constructors with the exact same number of arguments as the number of parameters passed into the constructor expression are considered potential matches.
A workaround could be to create a constructor that accepts a list and then modify your query to something along the lines of SELECT NEW EntityDTO(id, NEW list(date1, date2, date2))... if only nested NEW expressions were supported. Unfortunately, this is a long standing feature request.

How to use hasAnyRole like expression SpEl in #Query

I'm using Spring Security Expressions within #Query like this example:
#Query("select o from Pet o where o.owner.name like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.username}")
If you have the role ADMIN, the query returns all the pets. But if you don't have this role, the query returns only Pet objects where the owner name is the same of the user authenticated name.
This works fine, but when I try to use hasAnyRole('ROLE_ADMIN','ROLE_OWNER'), the system returns an exception...
org.springframework.expression.spel.SpelEvaluationException: EL1004E:(pos 0): Method call: Method hasAnyRole(java.lang.String,java.lang.String) cannot be found on java.lang.Object[] type
at org.springframework.expression.spel.ast.MethodReference.findAccessorForMetho
...
In SecurityExpressionRoot is defined the method hasAnyRole:
public final boolean hasAnyRole(String... roles) {
return hasAnyAuthorityName(defaultRolePrefix, roles);
}
I have the same issue, the quick workaround is to write hasRole('ROLE_SUPER') or hasRole('ROLE_OWNER').
This exception is caused by Spring Data, which is not able to resolve methods with a variable number of arguments in SpEL, as far as I can see when debugging.
The ExtensionAwareEvaluationContextProvider method resolver doesn't match hasAnyRole(String[]).
I created https://jira.spring.io/browse/DATACMNS-1518.
EDIT: this issue has been fixed, I just tested latest snapshot and got hasAnyRole work.

How to write Spring Data method name to retrieve all elements in a column?

Suppose I have the class:
#Entity
public class Bean {
#Id
private String beanId;
//other fields & setters and getters
}
And the corresponding Spring Data JPA repository, where I want to have in a List<String> all the beanIds.
#RepositoryDefinition(domainClass = Bean.class, idClass = String.class)
public interface BeanRepository {
#Query("select b.beanId from Bean b")
List<String> findAllBeanId();
}
As written above, everything works as expected; but this is a simple operation and I do not want to write a query explicitly. What should the name of the method be such that Spring Data can parse it and obtain the above mentioned query (or the same functionality). I have searched in both the reference documentation as two books I have on Spring Data. The above name (findAllBeanId) and others that I have tried (findBeanId, findBeanBeanId etc.) throw the following exception as root cause:
org.springframework.data.mapping.PropertyReferenceException: No property find found for type Trade
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:271)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:245)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:72)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:180)
at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:260)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:240)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:68)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:279)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:147)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:153)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:43)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 22 more
In the Spring docs: http://static.springsource.org/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html there is nothing about getting only particular column/property from entity by query generated from method name. So I think that currently it is not possible.
The code you showed works/should work as expected. It's simply not causing the exception you see :).
The exception is referring to a Trade, which seems to indicate that you have a repository for Trade somewhere which seems to refer to a missing property. The code you've shown is definitely not the one causing the exception. This can effectively not be the case as you're defining the query manually so that the query derivation mechanism doesn't even kick in for the repo you've shown.
I've pushed a test case for you to see this in action.

"Not supported for DML operations" with simple UPDATE query

I'm getting the error Not supported for DML operations when I use the following HQL...
#Query("UPDATE WorkstationEntity w SET w.lastActivity = :timestamp WHERE w.uuid = :uuid")
void updateLastActivity(#Param("uuid") String uuid, #Param("timestamp") Timestamp timestamp);
What could be causing the issue? It doesn't seem to be a common error given the few results I've found in Google.
Check the post hibernate hql ERROR: Not supported for DML operations in the hibernate users forum.
Most likely you called
querySt.list();
for your UPDATE query. Instead you should call
querySt.executeUpdate();
I was also having the same problem with annotations.After searching and doing some tricks I was able to solve it.
There are some below steps which you need to verify while using DML operation with JPA.
Use anotation
#Modifying(org.springframework.data.jpa.repository.Modifying) and #Transactional(org.springframework.transaction.annotation.Transactional) on required method.
Use void as return type of method.
e.g:-
#Modifying
#Query("UPDATE ProcedureDTO o SET o.isSelectedByUser =?1")
#Transactional
public void getListOfProcedureBasedOnSelection(Boolean isSelected);```
Make sure your service class method which calls updateLastActivity has #Transactional(org.springframework.transaction.annotation.Transactional) annotation. and modify the repository method to below,
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
...
#Modifying
#Query("UPDATE WorkstationEntity w SET w.lastActivity = :timestamp WHERE w.uuid = :uuid")
void updateLastActivity(#Param("uuid") String uuid, #Param("timestamp") Timestamp timestamp);
For more insights please use this answer.
I had exact same problem, in my case I had to only add #Modifying annotation. According to documentation:
Indicates a query method should be considered as modifying query as that changes the way it needs to be executed. This annotation is only considered if used on query methods defined through a Query annotation. It's not applied on custom implementation methods or queries derived from the method name as they already have control over the underlying data access APIs or specify if they are modifying by their name.
Queries that require a #Modifying annotation include INSERT, UPDATE, DELETE, and DDL statements.
The same happened to me because, being q an object of class Query, q.list() is not to be used for updates or deletes, but q.executeUpdate()

Categories

Resources