I'm trying to update every record for which I have the id in my arraylist but I'm getting this error:
IllegalStateException occured : org.hibernate.hql.QueryExecutionRequestException: Not supported for DML operations [update models.UserOnline uo SET currentRoom_id = :roomid where uo.id IN (:list)]
This is what I'm trying:
Query update_query = JPA.em().createQuery("update UserOnline uo SET currentRoom_id = :roomid where uo.id IN (:list)");
update_query.setParameter("roomid", null);
update_query.setParameter("list", idlist);
List<UserOnline> actual = update_query.getResultList();
Any ideas what's wrong?
I would try with update_query.executeUpdate();
From the docs.
Like Gonzalo already said, you'd have to use executeUpdate().
This is because you're actually MODIFYing data .
You only use getResultList() or getSingleResult() if you want to GET data out of the database.
a little helper:
use executeUpdate() if your query has the form
UPDATE ... SET .. WHERE ..
or
DELETE ... WHERE ...
use getResultList() or getSingleResult() if the query looks like
SELECT ... FROM xxx WHERE ...
or just
FROM xxx WHERE ...
Well, if we use Spring Repositories (CrudRepository or any of its type), and if we have a method declaration with an update Query
That is,
#Query("update employee e set e.name= :name where e.id = :id")
int updateEmployee(#Param("name") String name, #Param("id") Long id);
Then we will get the related Spring Exception org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations
Just add #Modifying annotation on the method and it will be fine.
Related
I have a requirement for a Input record with id1 from source, in target table I need to update value v1 in column c1 and in target for id1 there are multiple records. Using JPA I need to update all those records with value v1. Using JPA what is the best way to do this?
I used below
findallbyid() then saveall() - it failed saying there are mutliple records in target but expected was one.
Based on the details provided findallbyid() then saveall()
here the method findallbyid() is actually expecting to find only one record in the table, where as there are multiple rows.
changing the to signature of the method should work as expected without expection. As it expect capitalised words in method signature
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
List<T> findAllById(Long id);
but recommend not to read all rows and then save again just to update a column or two, you could use something like below to achieve the same
#Modifying
#Transactional
#Query(value = "UPDATE table t SET t.column = :status WHERE t.id = :id")
int update(#Param("status") String status, #Param("id") Long id);
I am trying to update the entities in a certain list using Spring Data JPA. However, I'm getting SQL Grammar Exception.
This is the method:
#Modifying
#Query("UPDATE Call c set c.locationLocked = false, c.locationLockedBy = null, c.locationLockedOn = null WHERE c.callIdentifier IN :timedOutLockedCallsIdentifiers AND c.audit.retired = false")
int expireTimedOutLockedCalls(#Param("timedOutLockedCallsIdentifiers") List<String> timedOutLockedCallsIdentifiers);
And this is the root cause:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near ")"
You are passing null or empty list in IN clause of the query.
Please check timedOutLockedCallsIdentifiers before calling above query.
It would probably be easier to do it more programatically then in a query
In your repository have the following
#Query("SELECT c FROM Call c WHERE c.callIdentifier IN :timedOutLockedCallsIdentifiers AND c.audit.retired = :retired")
List<Call> findByCallIdentifiers(List<String> timedOutLockedCallsIdentifiers, Boolean retired)
Then in your class
List<Call> updated = callRepo.findByCallIdentifiers(identifiers, false)
for(Call c : updated) {
c.setLocationLocked(false);
c.setLocationLockedBy(null);
c.setLocationLockedOn(null);
}
callRepo.saveAll(updated);
This will call the proper underlying updates as needed and cant let spring handle the query syntax properly
I have an Update Query that looks like this
UPDATE
table_name
SET
column_name = ?
WHERE
column_name = ? AND id in (?)
So the JPA transaction is
em.createNativeQuery(Update_QUERY)
.setParameter(1, updatedStatus)
.setParameter(2, currentStatus)
.setParameter(3, ids)
.executeUpdate();
The Input to the method is List id, currentStatus, and updatedStatus
How do I pass the List as a single parameter, if I convert the List to a comma-separated String I get the error Specified text is not number as strings is not allowed in the In clause.
How do I pass the List as a single parameter
An example approach:
String jpql = "UPDATE NameEntity ne " +
"SET ne.valstring = :updated_status " +
"WHERE ne.valstring = :current_status AND ne.id IN :ids";
em.createQuery(jqpl)
.setParameter("updated_status", updatedStatus)
.setParameter("current_status", currentstatus)
.setParameter("ids", Arrays.asList(ids))
.executeUpdate();
Three simple rules:
Use native SQL for bulk update / delete on tables that are not mapped to entities.
Native SQL queries work directly on database tables bypassing the persistence context (a set of managed entities), so it is safe to use such queries if a given database table has no corresponding entity.
Use JPQL for bulk update / delete on tables that are mapped to entities
In case of a given database table is mapped by an entity, using a SQL update / delete will lead to inconsistency between persistence context and the underlying database, so use JQPL counterparts instead and the persistence provider will take care of consistency.
Bulk update / delete should be executed as the first operation within the transaction or ideally in its own transaction.
Setting a List parameter
The JPA Query interface setParameter method that accepts an Object parameter:
Query setParameter(String name, Object value)
can take a List as the parameter value.
This works in the same way for JPQL, Criteria API, or bulk update and delete queries:
List<Post> posts = entityManager.createNativeQuery("""
UPDATE
post
SET
status = :newStatus
WHERE
status = :oldStatus AND
id IN :ids
""", Post.class)
.setParameter("oldStatus", PostStatus.PENDING)
.setParameter("newStatus", PostStatus.APPROVED)
.setParameter("ids", List.of(1L, 2L, 3L))
.executeUpdate();
For more details about executing bulk update and delete statements with JPA and Hibernate, check out this article as well.
I need to use the LIKE operator into an JPA query. I need to use it for types other then String but the JPA criteria API allows me to add only String parameters. I tried using the .as(String.class) but something fails and also tried calling the CAST function from the underlying Oracle that again fails for unknown reasons to me.
I tried writing the query also in JPQL and it works as expected. This is the query:
SELECT p from CustomerOrder p where p.id like '%62%'
UPDATE:
The query must be built in a generic fashion as it is for filtering, so it needs to be created at runtime. On the query that is already created I tried to add the LIKE clause like this:
query.where(builder.like(selectAttributePath.as(String.class), "%"+filterValue.toString().toLowerCase()+"%"));
But this crashes with this exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found '(' near line 1, column 156 [select distinct generatedAlias0.id from de.brueckner.mms.proddetailschedact.data.CustomerOrder as generatedAlias0 where cast(generatedAlias0.id as varchar2(255 char)) like :param0]
I executed the same query directly to Oracle using SQLDeveloper, so it should be sound from this point of view. So the problem is the Hibernate is the issue. Any suggestions on how to fix it?
How can I write this query using JPA Criteria?
I fixed the problem by invoking the 'TO_CHAR' function from the underlying Oracle DB and using the LIKE operator like for normal String's.
query.where(builder.like(selectAttributePath.as(String.class), "%" +filterValue.toString().toLowerCase() + "%")
You can try the below code, it might require modifications.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CustomerOrder> cq = cb.createQuery(CustomerOrder.class);
Root<CustomerOrder> order = cq.from(CustomerOrder.class);
cq.where(cb.like(Long.valueOf(order.get(CustomerOrder_.id)).toString(), "%62%"));
TypedQuery<CustomerOrder> q = em.createQuery(cq);
List<CustomerOrder> results = q.getResultList();
How to build valid HQL string, which is equivalent to
UPDATE table SET field = null WHERE ....
Do you mean bulk HQL update? Try this
UPDATE myEntity e SET e.myProperty = null WHERE ...
You can also use a parameterized version of the above
UPDATE myEntity e SET e.myProperty = :param WHERE ...
In your code:
int updatedEntities = session.createQuery(updateQueryHQL)
.setString( "param", myValue ) // or .setString( "param", null )
.executeUpdate();
See documentation for details.
If you're not doing bulk updates, you should just set your property to NULL and persist the entity normally.
Why does your update statement need to be done in HQL? Do you have this table mapped to an entity in the system? If you do, then you can simply set the property that maps to that column to null, and run a save on that entity. eg.
myObject.setMyProperty(null);
getSessionFactory().getCurrentSession().save(myObject);
That should work for you, but you gotta have an entity mapped to the table in question.