JPA: detached entity passed to persist: nested exception is org.hibernate.PersistentObjectException
At last, I got my solution for Many-to-Many connection in JPA.
Root Cause Analysis:
In a JPA many-to-many relationship, if cascade type has been set at CascadeType.PERSIST
(or CascadeType.ALL
, which includes CascadeType.PERSIST), then while saving the parent and updating it with references of the child, it will try to save the child again.
Following Issues can appear:
Child is already in persistence store (A detached instance has been passed)
-in this case it will throw an exception “org.hibernate.PersistentObjectException: detached entity passed to persist”
Solution:
Use this:
@ManyToMany(fetch = FetchType.EAGER,
cascade = {
CascadeType.MERGE,
CascadeType.REFRESH
})
@JoinTable(name = "commodity_genre", joinColumns = {
@JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = {
@JoinColumn(name = "genre_id", referencedColumnName = "id") })
@JsonManagedReference
private List<Genre> genres;
Instead of:
@ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.MERGE,
CascadeType.PERSIST
})
@JoinTable(name = "commodity_genre", joinColumns = {
@JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = {
@JoinColumn(name = "genre_id", referencedColumnName = "id") })
@JsonManagedReference
private List<Genre> genres;
For JPA, the best option would be to query for entity on the server side before trying to save it.
- If its sure that only new child will be added, and not a detached
instance from DB,
CascadeType.PERSIST
will take care of it. - On the other hand, if the requirement is never to add a new child if it's
not already in DB then
CascadeType.PERSIST
should be removed andcascade={CascadeType.MERGE,CascadeType.REFRESH}
should be used
Resource Link:
Persisting a detached entity in JPA
SkyWalker
This is Rizvi, Sr. Software Engineer(Java/J2EE Developer) at BJIT Ltd. 8+ years professional experience with proven SOLID knowledge of developing the project from scratch with agile methodologies, database optimization, performance tuning, version controlling using Git, SVN etc. Using Java Framework(Spring, Spring MVC, Spring Boot, GraphQL, Groovy, Struts) etc. I’m truly passionate about my work and always eager to learn new technologies. While I enjoy all aspects of my job, I think my favorite stage of a project is designing architecture. I would love to share my knowledge, potentially in a technical leadership role. I believe that If we share our knowledge, the world will be closer to us. For more, you can go to my blog: Rizvi's Blog You can support me at Patreon Become a Patron! ========================================== If you are looking for a different way to say Thanks, I also have: Amazon Wish List ========================================== #SOreadytohelp
Updated on June 04, 2022Comments
-
SkyWalker almost 2 years
JPA: many-to-many connection.
Scenerio:
Multiple product can be saved under multiple categories. Like: Mango can be used as Fruit category and Desert Category.
Product == [COMMODITY]
Category == [GENRE]
Exception:
detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist:
Commodity.java:
@Entity @Table(name = "COMMODITY") public class Commodity implements Serializable { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.AUTO) private Long id; ......... ......... @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST }) @JoinTable(name = "commodity_genre", joinColumns = { @JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "genre_id", referencedColumnName = "id") }) @JsonManagedReference private List<Genre> genres;
Genre.java:
@Entity @Table(name = "GENRE") public class Genre implements Serializable { private static final long serialVersionUID = 7643588406864492883L; @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.AUTO) private Long id; ......... ......... @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "genres") @JsonBackReference private List<Commodity> commodities;
My Action Plan:
- Check if you are trying to persist an entity which has the same id as another entity, and which is already present in the PersistenceContext in your application.
- Do not set an ID before you save or persist it. Hibernate will look at the Entity you’ve passed and it assumes that because it has its Primary Key populated that it is already in the database. Various blog and person, has given solution using removing setId()
But No luck. Getting stuck for hours. Any kind of help is highly appreciated.
Resource Link:
Hibernate / JPA – Detached entity passed to persist exception
For more, you can check full Exception Log:
01-04-2018 00:55:39 [g.a.c.CommodityController:55] addCommodity : addCommodity() method started!! 01-04-2018 00:55:39 [g.a.c.CommodityController:56] addCommodity : Full Model: Commodity [id=null, commodityName=Pant, price=345.0, unit=3, genres=null] 01-04-2018 00:55:39 [g.a.c.CommodityController:57] addCommodity : Genre Name is: Cloth 01-04-2018 00:55:39 [g.a.c.CommodityController:58] addCommodity : commodityName is: Pant 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:124] saveCommodities : saveCommodites called 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:113] checkGenreExistsInDB : checkGenreExistsInDB started Hibernate: select genre0_.id as id1_9_, genre0_.genre_name as genre_na2_9_ from genre genre0_ where genre0_.genre_name=? 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:118] checkGenreExistsInDB : checkGenreExistsInDB ended 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:133] saveCommodities : genre not Exists 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:135] saveCommodities : genre save in DB started Hibernate: insert into genre (genre_name) values (?) Hibernate: insert into commodity (commodity_name, price, unit) values (?, ?, ?) 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:137] saveCommodities : genre save in DB ended 01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:140] saveCommodities : Size of genreList: 1 Hibernate: insert into commodity (commodity_name, price, unit) values (?, ?, ?) 01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:58] runtimeExceptionHandle : org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:299) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy160.save(Unknown Source) at sari.account.dao.impl.CommodityDaoImpl.saveCommodities(CommodityDaoImpl.java:142) at sari.account.services.CommodityService.saveCommodities(CommodityService.java:31) at sari.account.controllers.CommodityController.addCommodity(CommodityController.java:59) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at sari.core.util.CorsConfiguration.doFilterInternal(CorsConfiguration.java:29) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:208) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:431) at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:363) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:278) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) at com.sun.proxy.$Proxy156.persist(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ... 76 more 01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:77] <init> : Status: 200 01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:78] <init> : Message : detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre 01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:79] <init> : Trace: Resource Not Available