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

Duvida de como pesistir duas entidades e ao mesmo tempo inserir a cheve estrangeira

Boa tarde, tenho duas entidades Usuario e Endereco cardinalidade de OneToOne, eu recebo esses dois objetos de um form, todas as informações.

classe Usuario :

package br.com.rprvidros.models;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
public class Usuario implements UserDetails{

    private static final long serialVersionUID = 1L;


    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    private String nome;
    private String senha;
    private String email;
    private String emailAlternativo;
    private String telefone;
    @OneToMany(fetch=FetchType.EAGER)
    private List<Role> roles = new ArrayList<Role>();
    @OneToMany(mappedBy = "id", targetEntity = PedidoItem.class)
    private List <Pedido> pedido;

    public List<Pedido> getPedido() {
        return pedido;
    }
    public void setPedido(List<Pedido> pedido) {
        this.pedido = pedido;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    public Integer getId() {
        return id;
    }
    public String getNome() {
        return nome;
    }
    @Override
    public String toString() {
        return "Usuario [id=" + id + ", nome=" + nome + ", senha=" + senha + ", email=" + email + ", emailAlternativo="
                + emailAlternativo + ", telefone=" + telefone + ", roles=" + roles + ", pedido=" + pedido + "]";
    }
    public void setNome(String nome) {
        this.nome = nome;
    }
    public String getSenha() {
        return senha;
    }
    public void setSenha(String senha) {
        this.senha = senha;
    }
    public String getTelefone() {
        return telefone;
    }
    public void setTelefone(String telefone) {
        this.telefone = telefone;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getEmailAlternativo() {
        return emailAlternativo;
    }
    public void setEmailAlternativo(String emailAleternativo) {
        this.emailAlternativo = emailAleternativo;
    }
    public List<Role> getRoles() {
        return roles;
    }
    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return this.roles;
    }
    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return senha;
    }
    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return email;
    }
    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }
    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return true;
    }
    public void setId(Integer id) {
        this.id = id;
    }

}

classe Endereco:

package br.com.rprvidros.models;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Endereco {

    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    private String cidade;
    private String uf;
    private String logradouro;
    private Integer numero;
    private String cep;
    private String complemento;

    @OneToOne
    private Usuario usuario;

    public String getCidade() {
        return cidade;
    }
    public void setCidade(String cidade) {
        this.cidade = cidade;
    }
    public String getUf() {
        return uf;
    }
    public void setUf(String uf) {
        this.uf = uf;
    }
    public String getLogradouro() {
        return logradouro;
    }
    public void setLogradouro(String logradouro) {
        this.logradouro = logradouro;
    }
    public Integer getNumero() {
        return numero;
    }
    public void setNumero(Integer numero) {
        this.numero = numero;
    }
    public String getCep() {
        return cep;
    }
    public void setCep(String cep) {
        this.cep = cep;
    }
    public String getComplemento() {
        return complemento;
    }
    public void setComplemento(String complemento) {
        this.complemento = complemento;
    }

    public void setUsuarioId(Integer id){
        this.usuario.setId(id);
    }        
}

aqui segue o controller que recebo os objetos:

controller:

@RequestMapping(method = RequestMethod.POST)
    public ModelAndView add(Usuario usuario, Endereco endereco){


        BCryptPasswordEncoder passwordEncoder = new                   BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(usuario.getSenha());
        usuario.setSenha(encode);


        Usuario usuarioCadastrado = dao.addUsuario(usuario);
        endereco.setUsuarioId(usuarioCadastrado.getId());
        eDao.addEndereco(endereco);

        return new ModelAndView("/rprvidros");

    }

eu recebo um NullPointerException, nessa linha ndereco.setUsuarioId(usuarioCadastrado.getId()); oq acho q faz sentido, poque ainda nao existe usuario inserido para eu pegar o ``ìd```, mas mesmo assim acho q isso é gambiarra, deve haver algum jeito "correto" de fazer isso.

obrigado

11 respostas

Bom dia Gabriel, faça seu DAO retornar um objeto managed, dai você consegue usa-lo para outra query depois. Ou pode buscar a id que foi adicionada no banco(provavelmente com auto incremet) e retornar apenas essa id

boa tarde guiherme, então oq eu fiz foi um metodo que retorna o ultimo usuario inserido no banco:

public Integer idLastUser(){
        return (Integer) manager.createQuery("select MAX(u.id) from Usuario u ").getSingleResult();
    }

mas acredito que não vai funcionar pois o usuario ainda nao vai estar no banco, não esse que esta sendo executado no mesmo metodo, do controller, outra coisa que estava pensando, na tabela de enderecoeu tenho uma foreign key chamada usuario_id, que esta representada assim na entidade endereco :

@OneToOne
    private Usuario usuario;

como faria essa inserção pelo java? eu criei na classe endereco o metodo :

public void setUsuarioId(Integer id){
        this.usuario.setId(id);
    }

isso funcionaria?

Assim, sempre trabalhamos com o objeto, então teu Endereco deve ter um Usuario e um setUsuario e nao id.

onde você está abrindo a transaction e commitando?

Entendi Guilherme, eu estou utilizando o Spring então esta configurado na classe JpaConfiguration, eu tenho um setUsuario, então no caso eu setaria o Usuario todo e só pegaria o Id, e depois como eu colocaria esse Id na coluna usuario_id, isso que não estou conseguindo entender, voce disse para retonar um objeto managed, isso seria quando eu for persistir, como eu faria isso?

Sim, me passa seu Dao por favor

Claro.

dao:

package br.com.rprvidros.daos;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import br.com.rprvidros.models.Endereco;
import br.com.rprvidros.models.Usuario;

@Repository
public class UsuarioDao implements UserDetailsService {

    @PersistenceContext
    private EntityManager manager;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        List<Usuario> usuarios = manager.createQuery("select u from Usuario u where u.email = " + email)
                .getResultList();

        if (usuarios.isEmpty()) {
            throw new RuntimeException("O usuario " + email + "não foi encontrado");
        }

        return usuarios.get(0);
    }

    public Usuario addUsuario(Usuario usuario) {

        manager.persist(usuario);        

        return usuario;
    }

    public Integer idLastUser(){
        return (Integer) manager.createQuery("select MAX(u.id) from Usuario u ").getSingleResult();
    }
}

Faz o seguinte, implementa o toString dos dois objetos, e imprime na controller assim:

Usuario usuarioCadastrado = dao.addUsuario(usuario);
System.out.println(usuarioCadastrado);
endereco.setUsuarioId(usuarioCadastrado.getId());
System.out.println(endereco);

E manda o console por favor

Guilherme segue o console:

Hibernate: insert into Usuario (email, emailAlternativo, nome, senha, telefone) values (?, ?, ?, ?, ?)
Usuario [id=55, nome=LUIZ OTAVIO REPRESENTACOES LTDA, senha=$2a$10$e50YCA93tF.JBe/gg1QZF.5.e3NLp91k9Hpxe2SSOkVxNnI5INNLO, email=gabriel_bartholo_batista@hotmail.com, emailAlternativo=gabriel_bartholo_batista@hotmail.com, telefone=2452345234, roles=[], pedido=null]

e logo em seguida ele da o java.lang.NullPointerException,

nessas linhas do endereco:

public void setUsuarioId(Integer id){
        this.usuario.setId(id);
    }

e nessa do proprio controller:

endereco.setUsuarioId(usuarioCadastrado.getId());
solução!

Vamos ver se oSpring está montando corretamente o objeto Endereco. Tira essa linha :

endereco.setUsuarioId(usuarioCadastrado.getId());

e imprime o toString do Endereco

Então Guilherme ele monta sim:

Hibernate: insert into Usuario (email, emailAlternativo, nome, senha, telefone) values (?, ?, ?, ?, ?)
Usuario [id=57, nome=LUIZ OTAVIO REPRESENTACOES LTDA, senha=$2a$10$mkLVDh19kOwefwvYHA9E4ulLzH6O4.eEK.o5fMEIzEb4r6IVv30eW, email=gabriel_bartholo_batista@hotmail.com, emailAlternativo=gabriel_bartholo_batista@hotmail.com, telefone=2452345234, roles=[], pedido=null]
Endereco [id=null, cidade=são paulo, uf=são paulo, logradouro=rua hiopdromo, numero=18, cep=0305100, complemento=null, usuario=null]

so que com o `usuario=null

Guilherme quando escrevi isso o usuario esta null, eu so adicionei endereco.setUsuario(usuarioCadastrado); e ele fez corretamente, o problema é que não estou pensando de forma de classe, porque a minha coluna no banco usuario_id e representada na classe endereco pelo atributo usuario então é simplesmente adicionar.

Valeu Guilherme sempre ajuda muito.