JPA: detached entity passed to persist: nested exception is org.hibernate.PersistentObjectException

14,692

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 and cascade={CascadeType.MERGE,CascadeType.REFRESH} should be used

Resource Link:

Persisting a detached entity in JPA

Share:
14,692
SkyWalker
Author by

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, 2022

Comments

  • SkyWalker
    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:

    1. 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.
    2. 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