Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

RELACIONAMENTO INCOMPLETO

Primeiramente gostaria de deixar registrado que estou achando este curso fraco. Parece que não foi revisado por ninguém.

No exemplo do exercício, só consegui executar após inserir a anotação @OneToOne no atributo titular da classe Conta e isto não foi demonstrado pelo professor.

Com relação ao relacionamento entre cliente e conta, a chave estrangeira só aparece na tabela Cliente. Na tabela Conta aparece como NULL.

1.Como corrigir isto? Uma hipótese tosca seria ter acesso a chave estrangeira e atualizar a conta a partir deste dado, mas penso que deva ter uma maneira mais inteligente de fazer isto.

  1. No exemplo, eu crio um Cliente a partir de uma Conta existente. E se eu quiser criar um novo cliente para uma nova conta?

  2. Quando eu tento criar uma Conta a partir de um cliente existente a aplicação ignora a anotação @JoinColumn(unique = true), independente se esta anotação seja inserida na classe Conta ou Cliente.

O instrutor faz uso do método setId como referência para persistir um cliente novo cliente. Isto é uma boa prática ? No meu entendimento, a chave primária não deveria ser alterada pela aplicação. O gerenciamento da chave primária deveria ficar apenas com o banco.

5 respostas

Oi Mauricio,

realmente teve uma confusão nessa aula. os videos estavam fora de ordem, mas já corrigi. De qq forma, já regravamos o curso e a nova versão deve ser lançada em breve.

Vamos as repostas:

0) A explicação sobre @OneToOne está aqui:

https://cursos.alura.com.br/course/jpa-hibernate-persistencia-objetos/task/71533

1) Um relacionamento @ManyToOne ou @OneToOnesó causa a criação de uma chave estrangeira em um único lado. No lado que possui a anotação.

2) Caso vc gostaria de criar uma nova conta E um novo cliente, ambas as entidades devem ser persistidas usando o método persist (pois elas estão no estado transiente).

3) Sobre o `joinColumn: ai precisa ver se a restrição foi gerada corretamente no banco. Talvez precise recriar o banco ou criar a restrição diretamente no mysql.

4) Sobre o setId: A principio é melhor deixar isso para hibernate e o banco, mas tem casos que pode ser util ter esse setId. Imagina que vc receba de um formulário html os dados de uma conta (com muitos campos) e essa conta já existe no banco. Nesse momento vc precisa popular a conta com os dados para atualizá-la no banco. Um framework MVC como Spring MVC já popula a conta sozinha, e ai basta chamar o merge (desde que a conta possui todas as infos). Alternativamente vc pode carregar a conta (find) e alterar os campos em questão chamando os setters. Ai nem precisa chamar merge ou setId (isso é o mais recomendado).

Tudo bem?

abs, Nico

Olá Nico,

Com relação ao relacionamento @OneToOne, no video da aula a anotação é inserida apenas no parâmetro conta da classe Cliente. Fazendo desta forma a aplicação retorna o seguinte erro:

xception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: alura] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1314)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1240)
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at br.com.alura.jpa.testes.TestaRelacionamentoClienteConta.main(TestaRelacionamentoClienteConta.java:13)
Caused by: org.hibernate.MappingException: Could not determine type for: br.com.alura.jpa.modelo.Cliente, at table: Conta, for columns: [org.hibernate.mapping.Column(cliente)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:488)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:455)
    at org.hibernate.mapping.Property.isValid(Property.java:227)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:624)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:267)
    at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:343)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:461)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1237)
    ... 4 more

O resultado correto só é alcançado fazendo o relacionamento bidirecional na classe Conta, conforme abaixo:

@OneToOne(mappedBy = "conta")
    private Cliente cliente;

Por que o relacionamento unidirecional não funciona ?

Oi Mauricio, nao precisa ser bidirecional! Basta tirar o atributo e a anotação na classe Conta.

abs

Obs: Quando vc faz esses testes, sempre "dropa" e recria as tabelas para ter certeza que vc tem um esquema limpo.

Olá Nico

Fazendo desta forma retornam as exceções que postei no comentário anterior. Este resultado foi obtido gerando novamente as tabelas.

solução!

Mauricio, tem como compartilhar codigo comigo? Talvez no github?

se nao tiver no github, pode entrar em contato comigo: nico.steppat@alura.com.br

abs

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software