0

I am learning Springboot and till now I have reached JPA. I am able to do CREAT/READ/DELETE operations. But for UPDATE for a certain condition, I am facing the issue. Let me elaborate below:

Rest API URL: http://localhost:8080/updateTopic?id=1

Request Body:

{
    "name": "Update Test",
    "description": "This is PUT"
}

Here I do not want to pass id in request body rather I want to pass only the rest. As JPA doesn't have any UPDATE operation so I have created a custom method in Repository. Below is my code in Repository class:

@Query("UPDATE Topic set name = :topic1.name, description = :topic1.description where id = :id")
void updateById(@Param("id") int id, @Param("topic") Topic topic1);

But with the above code I got this error antlr.NoViableAltException: unexpected AST node. So after looking for a while on Internet somewhere it told to change to this below:

@Query("UPDATE Topic set name = :#{#topic1.name}, description = :#{#topic1.description} where id = :id")
void updateById(@Param("id") int id, @Param("topic") Topic topic1);

But this one is giving a runtime error like this:

{
    "timestamp": "2021-03-22T12:48:21.582+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]; nested exception is java.lang.IllegalStateException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]",
    "trace": "org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]; nested exception is java.lang.IllegalStateException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]\r\n\tat org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:370)\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)\r\n\tat org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)\r\n\tat org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)\r\n\tat org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)\r\n\tat com.sun.proxy.$Proxy108.updateById(Unknown Source)\r\n\tat io.bootcamp.service.TopicServiceImpl.updateTopic(TopicServiceImpl.java:44)\r\n\tat io.bootcamp.controller.TopicController.updateTopic(TopicController.java:37)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:919)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:663)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:741)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\nCaused by: java.lang.IllegalStateException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1508)\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1553)\r\n\tat org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:214)\r\n\tat org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)\r\n\tat org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)\r\n\tat org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)\r\n\tat org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)\r\n\tat org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)\r\n\tat org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)\r\n\t... 65 more\r\nCaused by: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE io.bootcamp.model.Topic set name = :__$synthetic$__1, description = :__$synthetic$__2 where id = :id]\r\n\tat org.hibernate.hql.internal.ast.QueryTranslatorImpl.errorIfDML(QueryTranslatorImpl.java:314)\r\n\tat org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:365)\r\n\tat org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220)\r\n\tat org.hibernate.internal.SessionImpl.list(SessionImpl.java:1507)\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537)\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505)\r\n\t... 80 more\r\n",
    "path": "/updateTopic"
}

Any way by which I can achieve my aim ?

Barefaced Bear
  • 688
  • 1
  • 9
  • 30
  • Update your query then You can replace `@Param("topic") Topic topic1` with two separate parameters. `void updateById(@Param("id") int id, @Param("name") String name, @Param("description") String desc)` and then pass values accordingly. – Kaustubh Khare Mar 22 '21 at 13:12
  • @KaustubhKhare what if there are more than 4-5 columns. I want to make a generic solution – Barefaced Bear Mar 22 '21 at 13:36
  • Then the below solution is the way to achieve this. Find topic by id, update the required fields. You don't need to write a query for this one. Even you want to update multiple fields, you need to just call setter methods of the topic for those fields. – Kaustubh Khare Mar 22 '21 at 15:43

1 Answers1

0

There is no update method because Hibernate manages the entity for you.

Hibernate manages your entities for you. What this means is that any changes to existing entities are automatically passed through to the database, see the following SO answer: https://stackoverflow.com/a/13589352/6342972

So basically what you need to do is use the Topic findById(int id) method to find the specific Topic you want to update and then update the specific fields of that Topic. Those changes are then automatically persisted in the database by Hibernate.

  • can't I use custom query like the above I written & pass the values from the model ? – Barefaced Bear Mar 22 '21 at 13:12
  • Is there a specific reason you want to use a query to update an entity? Hibernate is more or less designed to update entities like I described. I suppose you could pass the values as separate parameters: `@Modifying @Query("UPDATE Topic t set t.name = :name, t.description = :description where id = :id") void updateById(@Param("id") int id, @Param("description") String description, @Param("name") String name);` – Wouter van der Linde Mar 22 '21 at 13:25
  • actually, I want to design the query as generic like for learning this is 2 columns but in the future, there can be more than 2 also. That's my new reason – Barefaced Bear Mar 22 '21 at 13:35