Hibernate: definindo uma foreing key com valor null

Java

14/08/2012

Bom, a situação é a seguinte:

Tenho uma tabela Pessoa, que tem uma foreign key da tabela Grupo.
Uma Pessoa pode pertencer à 1 Grupo, e 1 Grupo pode ter N Pessoas.

No banco de dados, defini que a FK id_grupo não é NOT NULL, portanto, era
para aceitar um null.
Tudo funciona bunitinho quando adiciono esse Grupo no cadastro da Pessoa.

O problema nasce quando eu tento adicionar uma pessoa sem definir um grupo para ela, eu recebo um erro
dizendo que devo persistir o objeto Grupo antes de referenciá-lo. Mas, eu NÃO quero referenciá-lo, uma vez que
ele é nulo.

O stacktrace é o seguinte:
    org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.jm.beans.Eleitor  
        org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:249)  
        org.hibernate.type.EntityType.getIdentifier(EntityType.java:456)  
        org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:276)  
        org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:286)  
        org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:294)  
        org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:3820)  
        org.hibernate.event.internal.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:536)  
        org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:243)  
        org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:172)  
        org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)  
        org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)  
        org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)  
        org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1127)  
        org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:325)  
        org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)  
        org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)  
        br.com.jm.dao.DemandaDAO.insert(DemandaDAO.java:28)  
        br.com.jm.factory.DemandaFactory.executeInsert(DemandaFactory.java:30)  
        br.com.jm.actions.DemandaAction.incluirDemanda(DemandaAction.java:129)  
        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)  
        com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:453)  
        com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:292)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:255)  
        org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)  
        com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)  
        org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)  
        com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)  
        com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)  
        com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:90)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)  
        com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:192)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)  
        com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)  
        org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)  
        org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:510)  
        org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:434)  


Já procurei em inúmeros fóruns, e o pessoal insiste em me aconselhar à usar um Cascade, mas isso não faz o menor sentido!
Eu não quero que ele insira no banco o objeto Grupo quando ele for nulo!!!

Será que alguem poderia me dar uma luz??
Renan Dantas

Renan Dantas

Curtidas 0

Melhor post

Davi Costa

Davi Costa

16/08/2012

Avaliando com calma seu log:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.jm.beans.Eleitor

Parace que vc pode ter dado algum new nesse atributo de grupo, no objeto que vc quiz salvar no banco. verifica isso, se for o casobasta colocar null nesse atributo antes de salvar.

att Davi
GOSTEI 1

Mais Respostas

Davi Costa

Davi Costa

14/08/2012

posta os dois mapemanetos aqui.Vai ficar mais fácil para te ajudar

att Davi
GOSTEI 0
Renan Dantas

Renan Dantas

14/08/2012

Aqui vão as classes:

Classe Eleitor:
    package br.com.jm.beans;  
      
    import java.io.Serializable;  
    import java.text.DateFormat;  
    import java.text.DecimalFormat;  
    import java.text.ParseException;  
    import java.text.SimpleDateFormat;  
    import java.util.ArrayList;  
    import java.util.Date;  
    import java.util.List;  
    import javax.persistence.CascadeType;  
    import javax.persistence.Column;  
    import javax.persistence.Entity;  
    import javax.persistence.FetchType;  
    import javax.persistence.GeneratedValue;  
    import javax.persistence.GenerationType;  
    import javax.persistence.Id;  
    import javax.persistence.JoinColumn;  
    import javax.persistence.JoinTable;  
    import javax.persistence.ManyToMany;  
    import javax.persistence.ManyToOne;  
    import javax.persistence.OneToMany;  
    import javax.persistence.Table;  
    import javax.persistence.Temporal;  
    import javax.persistence.TemporalType;  
    import javax.persistence.Transient;  
      
      
    @Entity  
    @Table(name=eleitor)  
    public class Eleitor implements Serializable{  
        private static final long serialVersionUID = -6226011868072777381L;  
        @Id  
        @GeneratedValue(strategy=GenerationType.AUTO)  
        @Column(name=id_eleitor)  
        private Integer idEleitor;  
        @ManyToOne(fetch=FetchType.EAGER)  
        @JoinColumn(name=id_cidade)  
        private Cidade cidade;  
        @ManyToOne(fetch=FetchType.EAGER)  
        @JoinColumn(name=id_grupo)  
        private Grupo grupo;  
        @Column(name=el_nome)  
        private String nome;  
        @Column(name=el_apelido)  
        private String apelido;  
        @Column(name=el_sexo)  
        private String sexo;  
        @Column(name=el_data_nasc)  
        @Temporal(TemporalType.DATE)  
        private Date dataNasc;  
          
            //INFINIDADE DE VARIÁVEIS  
      
        @ManyToMany(cascade={CascadeType.MERGE,CascadeType.REMOVE},fetch=FetchType.LAZY)  
        @JoinTable(name=cursos_eleitor,  
        joinColumns = @JoinColumn(name=id_eleitor, referencedColumnName=id_eleitor),  
        inverseJoinColumns = @JoinColumn(name=id_curso, referencedColumnName=id_curso))  
        private ListCurso listaCursos = new ArrayListCurso();  
        @OneToMany(mappedBy=eleitor, cascade={CascadeType.MERGE,CascadeType.REMOVE},fetch=FetchType.LAZY)  
        private ListCampanhasEleitor listaCampanhasEleitor = new ArrayListCampanhasEleitor();  
        @OneToMany(mappedBy=eleitor, cascade={CascadeType.MERGE,CascadeType.REMOVE},fetch=FetchType.LAZY)  
        private ListExperiencia listaExperiencias = new ArrayListExperiencia();  
        @OneToMany(mappedBy=eleitor, cascade={CascadeType.MERGE,CascadeType.REMOVE},fetch=FetchType.LAZY)  
        private ListDemanda listaDemandas = new ArrayListDemanda();  
        @Transient  
        private DateFormat sdf = new SimpleDateFormat(dd/MM/yyyy);  
        @Transient  
        private DecimalFormat df = new DecimalFormat();  
        @Transient  
        private String dia;  
        @Transient  
        private String mes;  
        @Transient  
        private String ano;  
          
        //------------------------Getters e Setters--------------------------------  
    }  


Classe Grupo:

    package br.com.jm.beans;  
      
    import java.io.Serializable;  
    import javax.persistence.Column;  
    import javax.persistence.Entity;  
    import javax.persistence.GeneratedValue;  
    import javax.persistence.GenerationType;  
    import javax.persistence.Id;  
    import javax.persistence.Table;  
      
    @Entity  
    @Table(name = grupo)  
    public class Grupo implements Serializable {  
        private static final long serialVersionUID = -7112823581533993573L;  
        @Id  
        @GeneratedValue(strategy=GenerationType.AUTO)  
        @Column(name = id_grupo)  
        private Integer idGrupo;  
        @Column(name = gp_nome)  
        private String nome;  
          
        public Grupo(){  
              
        }  
      
        //GETTERS E SETTERS  
    }  


O mesmo acontece com outra classe que tem relacionamento com Eleitor, a classe Demanda.
Nesta classe, é o Eleitor que deveria ser nulo dentro da Demanda, porém, recebo o mesmo stacktrace
ao tentar gravar uma Demanda com uma FK de Eleitor sendo nula.

Classe Demanda:
    package br.com.jm.beans;  
      
    import java.io.Serializable;  
    import java.text.SimpleDateFormat;  
    import java.util.ArrayList;  
    import java.util.Date;  
    import java.util.List;  
    import javax.persistence.CascadeType;  
    import javax.persistence.Column;  
    import javax.persistence.Entity;  
    import javax.persistence.FetchType;  
    import javax.persistence.GeneratedValue;  
    import javax.persistence.GenerationType;  
    import javax.persistence.Id;  
    import javax.persistence.JoinColumn;  
    import javax.persistence.ManyToOne;  
    import javax.persistence.OneToMany;  
    import javax.persistence.Table;  
    import javax.persistence.Transient;  
      
    @Entity  
    @Table(name=demanda)  
    public class Demanda implements Serializable{  
        private static final long serialVersionUID = 4959562413119839409L;  
        @Id  
        @GeneratedValue(strategy=GenerationType.AUTO)  
        @Column(name=id_demanda)  
        private Integer idDemanda;  
        @ManyToOne(fetch=FetchType.EAGER)  
        @JoinColumn(name=id_eleitor, nullable=true)  
        private Eleitor eleitor;  
        @Column(name=dm_solic)  
        private String solic;  
        @Column(name=dm_obs)  
        private String obs;  
        @Column(name=dm_status)  
        private String status;  
        @OneToMany(mappedBy=demanda, fetch=FetchType.EAGER, cascade={CascadeType.DETACH,CascadeType.REMOVE})  
        private ListOcorrencia listaOcorrencias;  
        @Transient  
        private SimpleDateFormat sdf = new SimpleDateFormat(dd/MM/yyyy);  
        @Transient  
        private Date periodoIni;  
        @Transient  
        private Date periodoFin;  
          
        //GETTERS E SETTERS  
    }  


Dei uma olhada no meu banco, e na tabela Eleitor, a chave extrangeira referente ao Grupo estava com cascade definido como RESTRICT.
Fiz a alteração e vou testar agora, mas não creio que isso irá surtir efeito, uma vez que na tabela Demanda, o cascade está como NO ACTION
e ainda assim tenho o mesmo resultado.
GOSTEI 0
Robson Teixeira

Robson Teixeira

14/08/2012

verifique o mapeamento de cascade nas suas classes de entidade, principalmente o cascade e também verifique se não ha atributo com anotação @NotNull ou @NotEmpty.
GOSTEI 0
Renan Dantas

Renan Dantas

14/08/2012

Davi, acertou em cheio no problema cara!

Só que em momento nenhum eu dei um new nesse objeto. Porém, antes de executar o persist, verifiquei se o objeto era
realmente nulo, ou se era um objeto Grupo com dados nulos, daí funcionou!

Brigadão cara!
GOSTEI 0
Davi Costa

Davi Costa

14/08/2012

Show de bola Renan!
Sucesso, precisando é só postar aqui.

att Davi
GOSTEI 0
POSTAR