Hibernate: Error trying to persist field that maps foreign key

2

In my current Spring project, I'm facing the following issues when trying to save an entity that references another (with foreign key), with this:

@Entity
@Table(name="pagina")
public class Pagina {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "nome", length=32, nullable=false, unique=true)
    @Order(value=1)
    private String nome;

    @Column(name = "titulo", length=32, nullable=false)
    @Order(value=2)
    private String titulo;

    @Column(name = "descricao", length=65535)
    @Order(value=4)
    private String descricao;

    @OneToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinColumn(name="pagina_mae")
    @Order(value=5)
    private Pagina pagina;

    @OneToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinColumn(name="produto_mae")
    @Order(value=6)
    private Produto produto;
}

The fields pagina and produto are mapped to my view like this:

<form:label path="pagina.id" class="label label-default">Pagina</form:label>
<form:select path="pagina.id" class="form-control select" data-lista="/Pagina/listagem"/>

select options are added via this javascript code:

$("select.select").each(function(){
    var target = $(this);
    var lista = $(this).data('lista');
    load_options(target, lista);
});

function load_options(target, lista) {
    target.empty();
    target.append('<option></option>');
    $.ajax({
        type: 'GET',
        url: lista
    }).done(function(data){
        var json = jQuery.parseJSON( data );
        $.each(json.item, function(index, item) {
            target.append('<option class="form-control" value="'+item.id+'">'+item.nome+'</option>');
        });
    });
}

The problem is when I try, for example, to save a Page with one of the selected Pages options in the database. In this case the application shows the following error message:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.spring.loja.model.pagina.persistence.model.Pagina; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.spring.loja.model.pagina.persistence.model.Paginaorg.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:185)org.springframework.orm.hibernate4.HibernateExceptionTranslator.convertHibernateAccessException(HibernateExceptionTranslator.java:57)org.springframework.orm.hibernate4.HibernateExceptionTranslator.translateExceptionIfPossible(HibernateExceptionTranslator.java:44)org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.pagina.persistence.PaginaHome$$EnhancerBySpringCGLIB$$93c6b425.persist(<generated>)com.spring.loja.config.generic.service.service.cadastra(service.java:45)com.spring.loja.config.generic.service.service$$FastClassBySpringCGLIB$$c92a3159.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.pagina.service.PaginaService$$EnhancerBySpringCGLIB$$50173e86_2.cadastra(<generated>)com.spring.loja.config.generic.controller.controller.cadastra(controller.java:42)com.spring.loja.config.generic.controller.controller$$FastClassBySpringCGLIB$$c8cc444b.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)com.spring.loja.model.pagina.controller.PaginaController$$EnhancerBySpringCGLIB$$a46b2130_2.cadastra(<generated>)sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)java.lang.reflect.Method.invoke(Unknown Source)org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)javax.servlet.http.HttpServlet.service(HttpServlet.java:647)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)

If I do not select any option, this is the error message shown:

org.hibernate.PropertyValueException: not-null property references a null or transient value : com.spring.loja.model.pagina.persistence.model.Pagina.nomeorg.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:106)org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:132)org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:86)org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:314)org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:432)org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)com.spring.loja.config.generic.persistence.Dao.persist(Dao.java:32)com.spring.loja.config.generic.persistence.Dao$$FastClassBySpringCGLIB$$ddbbe880.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.pagina.persistence.PaginaHome$$EnhancerBySpringCGLIB$$93c6b425.persist(<generated>)com.spring.loja.config.generic.service.service.cadastra(service.java:45)com.spring.loja.config.generic.service.service$$FastClassBySpringCGLIB$$c92a3159.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.pagina.service.PaginaService$$EnhancerBySpringCGLIB$$50173e86_2.cadastra(<generated>)com.spring.loja.config.generic.controller.controller.cadastra(controller.java:42)com.spring.loja.config.generic.controller.controller$$FastClassBySpringCGLIB$$c8cc444b.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)com.spring.loja.model.pagina.controller.PaginaController$$EnhancerBySpringCGLIB$$a46b2130_2.cadastra(<generated>)sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)java.lang.reflect.Method.invoke(Unknown Source)org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)javax.servlet.http.HttpServlet.service(HttpServlet.java:647)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
I understand that when I send an entity to the server without having selected a select option, the application is trying to create a new entity with blank data when it should save the entity with the null value to the field left in open.

What would be the correct way to save the entity in question, selecting or not one of the available options for the field?

    
asked by anonymous 06.08.2014 / 18:35

1 answer

1

The problem is caused because the instances used in relationships are not JPA entities.

Objects are already out of EntityManager . When you select an item from Produto or pagina , it has been retrieved from a previous connection. When the connection or transaction is terminated, the objects are in the detached state. When you select an empty item, the framework probably creates an empty instance. All this explains the reason for the different errors.

I do not remember a direct solution to this, after all the JPA and its implementations are full of peculiarities.

However, one solution I've seen a few times is to change your save method to update related entities. For example:

//verifica se tem algum produto selecionado
if (pagina.getProduto().getId() == null || pagina.getProduto().getId().isEmpty()) {
    //se for vazio, retira o produto
    pagina.setProduto(null);
} else {
    //se existe um produto, então recupera a entidade verdadeira
    pagina.setProduto(em.find(Produto.class, pagina.getProduto().getId()));
}

//TODO fazer o mesmo com a pagina "mãe": pagina.getPagina()

//agora os relacionamentos não estarão detached
em.persist(pagina);
    
09.08.2014 / 01:11