Re:Hibernate - TransientObjectException - bug no HB?

17 respostas
A

Já tentou comentar a linha:

Apenas para ver se o erro continua? Se desaparecer, então o hibernate está realmente chamando o seu getCity() e guardando a nova instância de CityVO criada no código acima, antes de persistir… Como não existe cascade para o seu relacionamento @ManyToOne, ele dá esse erro porque tenta atualizar o relacionamento entre o AddressVO e um CityVO que não existe no banco…

17 Respostas

A

Já tentou usar assim (tirar as anotações do método p/ o atributo)? Apenas um teste...

@Entity
@Table(name = "ADDRESS", uniqueConstraints = {})
public class AddressVO {
    @ManyToOne(cascade = {}, fetch = FetchType.LAZY)
    @JoinColumn(name = "FK_ID_CITY")
   private CityVO city;

    public CityVO getCity() {
        if(isLazy() && this.city == null) {
            this.city = new CityVO();
        }

        return this.city;
    }

    public void setCity(CityVO city) {
        this.city = city;
    }
}
jgbt

Cara,
isso não tem a ver com Lazy, mas com cascade.
Esse erro acontece qunado vc tenta salvar um entity que possui um relacionamento com outro entity e esse relaionamento ainda não esta salvo.
Ou seja, para salvar um entity que possui uma instancia de outro entity, essa instancia ja deve estar salva.
por exemplo:

Pessoa p = new Pessoa("Ze");
Endereco e = new Endereco("Rua Um, 12");

session.save(e);

p.setEndereco(e);

session.save(p);

Nesse exemplo se eu quisess salvar o objeto Pessoa ja com o Endereco associado, eu teria que mapear com CascadeType.PERSIST ou CascadeType.ALL.

De uma lida na documentação do hibernate, vai te ajudar.

[]´s

pimentaft

Eu tbm to com esse problema no cascade…

jgbt

alancq:
Já tentou usar assim (tirar as anotações do método p/ o atributo)? Apenas um teste…

Isso não faz diferença nenhuma.

[]s

jgbt

Vamos por partes:
Mapear no atributo ou no metodo get, nao faz diferenca.
Se o erro mudou, com certeza nao foi por causa disso.

Quanto ao relacionamento:
Eu posso persistir o objeto pai sem ter uma instancia do filho. So vou ficar sem o relacionamento.
O fato do relacionamento estar null não é problema.

Se vc for persistir o objeto pai e esse codigo der true:

if(isLazy() && this.city == null) {  
             this.city = new CityVO();  
         }

o erro vai ocorrer, pq seu CityVO não esta associado a session do hibernate.
Fico pensando pq vc precisa inicializar o relacionamento com um objeto vazio…

[]´s

jgbt

Bom… parece que não funciona perfeitamente então.

Se vc tirar essa parte que “funciona perfeitamente” o que acontece?

[]´s

jgbt

Não fica nervoso cara…

Acho que quem não le o que ta escrito é vc

Se eu adiciono alguma coisa ao meu codigo e um simples 1-N não funciona, acho que alguma coisa esta errado, certo?

E eu fiz uma pergunta clara e direta, se vc retirar a parte do codigo que vc diz que funciona perfeitamente o que acontece?
Pq se funcionar, me parece obvio que o problema esta nessa parte do codigo.

No mais… boa sorte

[]´s

fredye

Galera se alguém puder me auxiliar estou passando pelo mesmo problema.

E só falta isso pra finalizar o sistema.

Meu cenário e o seguinte.

Tenho uma classe Aluno no seguinte formato:

@Entity  
@Table(name = "aluno", catalog = "baselibrus")  
public class Aluno implements java.io.Serializable {  
  
    private Integer idAluno;  
    private String nome;  
      
        private List<Reserva> reservas;  
      
    public Aluno() {  
      
    }  
  
    @Id  
    @GeneratedValue(strategy = IDENTITY)  
    @Column(name = "idAluno", unique = true, nullable = false)  
    public Integer getIdAluno() {  
        return idAluno;  
    }  
  
    public void setIdAluno(Integer idAluno) {  
        this.idAluno = idAluno;  
    }  
  
    @Column(name = "nome", length = 45)  
    @Length(max = 45)  
    @NotEmpty  
    public String getNome() {  
        return this.nome;  
    }  
  
    public void setNome(String nome) {  
        this.nome = nome;  
    }  
  
    @OneToMany(cascade = CascadeType.PERSIST, fetch=FetchType.EAGER,mappedBy ="aluno")  
    public List<Reserva> getReservas() {  
        return reservas;  
    }  
  
    public void setReservas(List<Reserva> reservas) {  
        this.reservas = reservas;  
    }  
      
}

Uma classe Reserva no seguinte formato:

view plaincopy to clipboardprint?
@Entity  
@Table(name = "reserva", catalog = "baselibrus")  
public class Reserva implements java.io.Serializable {  
  
    private Integer id;  
    private Aluno aluno;      
    private Livro livro;   
      
      
    public Reserva() {  
    }  
  
    @Id  
    @GeneratedValue(strategy = IDENTITY)  
    @Column(name = "id", unique = true, nullable = false)  
    public Integer getId() {  
        return this.id;  
    }  
  
    public void setId(Integer id) {  
        this.id = id;  
    }  
  
      
    @ManyToOne  
    @JoinColumn(name="idAluno", insertable = true, updatable = true)  
    public Aluno getAluno() {  
        return aluno;  
    }  
  
    public void setAluno(Aluno aluno) {  
        this.aluno = aluno;  
    }  
  
      
    @ManyToOne  
    @JoinColumn(name="idLivro", insertable = false, updatable = false)  
    public Livro getLivro() {  
        return livro;  
    }  
  
    public void setLivro(Livro livro) {  
        this.livro = livro;  
    }  
  
}

E por fim uma classe chamada Livro:

view plaincopy to clipboardprint?
@Entity  
@Table(name = "livro", catalog = "baselibrus")  
public class Livro implements java.io.Serializable {  
  
    private Integer idLivro;  
    private List<Reserva> reservas;  
      
      
    public Livro() {  
    }  
  
      
    @Id  
    @GeneratedValue(strategy = IDENTITY)  
    @Column(name = "idLivro", unique = true, nullable = false)  
    public Integer getIdLivro() {  
        return idLivro;  
    }  
  
    public void setIdLivro(Integer idLivro) {  
        this.idLivro = idLivro;  
    }  
  
      
        @OneToMany(cascade = CascadeType.PERSIST, fetch=FetchType.EAGER, mappedBy ="livro")  
    public List<Reserva> getReservas() {  
        return reservas;  
    }  
  
    public void setReservas(List<Reserva> reservas) {  
        this.reservas = reservas;  
    }  
  
}

A classe Reserva se relaciona com Aluno e Livro, mas quando tento persistir uma ID para Aluno e uma ID para Livro recebo

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing:

theBalrog

Boa tarde, pessoal.

Estou com um problema ao trabalhar com o Hibernate. Possuo uma classe chamada CityVO que está perfeitamente mapeada. Tenho também uma classe chamada AddressVO que é basicamente conforme abaixo:
@Entity
@Table(name = "ADDRESS", uniqueConstraints = {})
public class AddressVO {
   private CityVO city;

    @ManyToOne(cascade = {}, fetch = FetchType.LAZY)
    @JoinColumn(name = "FK_ID_CITY")
    public CityVO getCity() {
        if(isLazy() && this.city == null) {
            this.city = new CityVO();
        }

        return this.city;
    }

    public void setCity(CityVO city) {
        this.city = city;
    }
}

Só pra justificar, esse isLasy() funciona porque eu tenho uma particularidade no sistema que requer que eu faça isso.
Bem, tudo sempre foi muito bonito. O problema é que eu tenho um processo bem complexo de importação de dados vindos do Excel e estou tendo o seguinte erro:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.singlepoint.crm.vo.CityVO

Imaginei, ele deve estar ferrando em algum momento, e instanciando um CityVO. Mas debugando, descobri que isso não é verdade. Esse erro acontece no meu save (que já faz flush) e a referência para o CityVO está null.

Como proceder? Sempre pego problemas absurdos e sem sentido.
Um abraço a todos e desde já obrigado.

theBalrog

up!

theBalrog

Fala alancq,

Veja: esse teste eu fiz ontem no final do dia. E funcionou.
Só que o que me espanta é: se a propriedade lazy do meu AddressVO está falso e a referência para CityVO está null, como é possível existir uma instância?

Estou quase decidindo mudar a aplicação para não usar esse método de criação tardia.

Mas sinceramente, será que é um bug no Hibernate? Ou trata-se de como ele trabalha internamente? Porque a única maneira que eu vejo de o lazy ser true e, com isso, criar uma instância de CityVO é se o Hibernate criar outra instância de AddressVO (no momento de salvar na Session) e copiar os atributos para a nova instância (isso até faz sentido, porque o atributo lazy está marcado como @Transient).
Mas se isso for verdade, como que a minha referência original é a mesma que a gerenciada pelo Hibernate? Isso é muito nebuloso… E o pessoal dos fóruns do HB não responderam ainda.

Mesmo assim… Vou continuar nessa tentativa… Obrigado cara…

theBalrog

Ficou estranho o reply…

Joguei para o final… :lol:

theBalrog

Olha cara…
Francamente nem tentei porque não achei que faria diferença…
Mas qual não foi a surpresa quando eu mudei e, ao testar, retornou a seguinte mensagem:

2008-11-19 13:42:43,468 WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 904, SQLState: 42000
2008-11-19 13:42:43,468 ERROR org.hibernate.util.JDBCExceptionReporter - ORA-00904: “ADDRESSVO1_”.“CITY”: identificador inválido

Não teria que ter alguma anotação na entidade indicando que os mapeamentos estão em atributos e não getter methods?

Um abraço, e obrigado de novo.

jgbt:
Cara,
isso não tem a ver com Lazy, mas com cascade.
Esse erro acontece qunado vc tenta salvar um entity que possui um relacionamento com outro entity e esse relaionamento ainda não esta salvo.
Ou seja, para salvar um entity que possui uma instancia de outro entity, essa instancia ja deve estar salva.

Cara, desculpa a pergunta, mas você leu o que eu falei? Ou você deu reply só por ter lido o nome da Exception?
Eu sei que esse problema é por conta de não ter salvo a dependência. Se liga no que eu escrevi no tópico:

Nesse caso, como eu vou persistir um objeto que está null? Não conheço nenhuma forma… Se você conseguir, me dá um toque… E outra coisa… Quando cito o lazy no tópico e nos posts, não me refiro ao Lazy-Fetching do Hibernate, mas sim da estratégia de inicialização tardia do CityVO constante na minha associação.

Obrigado pelo toque, embora sinceramente eu tenho o bom hábito de ler a documentação antes de postar em fóruns… Tanto é verdade que você vai ver pouquíssimos tópicos meus, e os que existem, raramente alguém ajuda, tamanho é o problema.

jgbt:
alancq:
Já tentou usar assim (tirar as anotações do método p/ o atributo)? Apenas um teste…

Isso não faz diferença nenhuma.

[]s


Também achava que não… MAS, como pode ver no início desse post, mudou com certeza… Tendo visto pelo erro que o Hibernate me passou no console. ISSO porque eu não coloquei o trace do SQLException que apareceu.

De qualquer forma, obrigado mesmo assim.

theBalrog

Concordo… Vamos por partes…

jgbt:
Vamos por partes:
Mapear no atributo ou no metodo get, nao faz diferenca.
Se o erro mudou, com certeza nao foi por causa disso.

Também fiquei tão cético quanto você… Mas REALMENTE só mapeei pelo atributo ao invés de pelo método getter.

Pois é cara… Também falei que, durante o debug, descobri que o isLazy() retorna false, o que invalida a possibilidade que você citou.
Francamente, esses erros primários já foram cobertos, cara. A menos que seja tão primário que ninguém esteja conseguindo enxergar.

Pois é… Também falei que é necessidade da minha aplicação. Que funciona perfeitamente, diga-se de passagem. Só dá problema nesse procedimento.

Um abração e obrigado pela ajuda.

theBalrog

jgbt:
theBalrogg:

Pois é… Também falei que é necessidade da minha aplicação. Que funciona perfeitamente, diga-se de passagem. Só dá problema nesse procedimento.

Bom… parece que não funciona perfeitamente então.

Se vc tirar essa parte que “funciona perfeitamente” o que acontece?

[]´s


Caramba hein João… Não queria ter que falar assim, mas você não consegue ler tudo que eu escrevo? Ou você dá uma de João-Sem-Braço e ignora, só pra me dar chance de explicar de novo (ou quem sabe desenhar né).

Como eu disse, e você mesmo quotou, A aplicação funciona perfeitamente, e não “perfeitamente”. Essa funcionalidade que foi incluída está dando problema, e é por causa disso.

Já sei, agora vamos começar a discutir o que cada um aqui entende por “funciona perfeitamente”. Na boa, agradeço a compreensão, mas despenso essa discussão. Se você quiser mesmo discutir isso, eu crio um tópico off-topic só pra podermos falar sobre isso. Enquanto isso, continuo com o meu problema.

De novo, agradeço as suas tentativas nobres em me ajudar.
Vejam bem: estou mudando o foco da discussão para o problema, e não para o que o colega João (jgbt) acha que é perfeito.

De novo, agradeço a ajuda de todos.

theBalrog

Não fica nervoso cara…

Acho que quem não le o que ta escrito é vc

Se eu adiciono alguma coisa ao meu codigo e um simples 1-N não funciona, acho que alguma coisa esta errado, certo?

E eu fiz uma pergunta clara e direta, se vc retirar a parte do codigo que vc diz que funciona perfeitamente o que acontece?
Pq se funcionar, me parece obvio que o problema esta nessa parte do codigo.

No mais… boa sorte

[]´s

Nem to nervoso cara… Se estivesse, eu já teria parado de responder…
E não é o 1-N que não funciona. Poxa, você não entendeu o problema ainda?

Eu tenho uma instância de AddressVO. Estou prestes a salvar essa instância na Session do Hibernate. Debugando, descobri que a propriedade lazy do meu AddressVO está como false e que o atributo city do meu AddressVO aponta para null. Como você sabiamente observou, por não existir regra de Cascade nesse @ManyToOne, se o objeto que eu referencio (CityVO) não for persistido antes, eu terei o TransientObjectException. Mas como eu já falei, a referência está null. A FK no banco deveria ficar NULL. Está tudo certo. O problema é que o Hibernate, de alguma forma, está criando esse CityVO em algum momento após o flush().

Note que eu nem estou culpando o Hibernate, até mesmo porque se for eu que estiver fazendo merda, eu arrumaria o que tivesse que arrumar; mas eu quero saber pelo menos porque o que eu estou fazendo é uma merda.

Quer saber o resultado de um teste que eu fiz?

public CityVO getCity() {
    if(isLazy() && this.city == null) {
        this.city = new CityVO();
    }

   return this.city;
}

Coloque um breakpoint na terceira linha (que é onde eu instancio um CityVO se a propriedade lazy estiver true (lembrando que está FALSE).
Debugando no Eclipse 3.4.1 (Ganymede), em nenhum momento o depurador parou nessa linha.

Será que eu consegui transcrever o cenário completo, dessa vez?

Respondendo à sua pergunta, se eu retirar o código que funciona perfeitamente vai parar de funcionar. Mas sinceramente não entendi a sua pergunta… É como falar: se no seu ERP você remover o módulo de Notas Fiscais, esse módulo vai continuar funcionando?

Um abraço. Sorte? Pelo jeito estou precisando… Embora pelo menos neste tópico estou tendo resposta… No fórum do Hibernate não tive nenhuma notícia…

theBalrog

Bom, apenas para constar, meu prazo para tentativas se esgotou.
Acabei tendo que remodelar algumas coisas, fazer algumas gambiarras (o que eu desaprovo absolutotalmente) e no final, agora tudo funciona.

No entanto, a raiz do problema ainda não foi identificada. De qualquer maneira, vou considerar esse problema como resolvido.
Obrigado pela atenção de todos e um grande abraço aos que postaram tentando me ajudar.

Até mais.

Criado 19 de novembro de 2008
Ultima resposta 19 de nov. de 2008
Respostas 17
Participantes 5