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

Erro ao tentar persistir entidade com relacionamento @ManyToOne

Boa tarde,

estou recebendo o erro:

Cannot add or update a child row: a foreign key constraint fails (`rprvidros`.`pedidoitem`, CONSTRAINT `FK_hamfb5ev3u7p1c8yixhcs6o9o` FOREIGN KEY (`id`) REFERENCES `pedido` (`id`))

ao tentar persistir a entidade pedido:

package br.com.rprvidros.models;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.persistence.Entity;
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.Temporal;
import javax.persistence.TemporalType;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

@Entity
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION)
public class Pedido {



    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    @Temporal(TemporalType.DATE)
    private Date data_pedido;
    private String status;
    private String pagamento;
    @ManyToOne
    @JoinColumn(name="usuario_id")
    private Usuario usuario;
    @OneToMany(mappedBy = "id", targetEntity = PedidoItem.class)
    private Map<PedidoItem,Integer> itens = new LinkedHashMap<PedidoItem,Integer>();


    @Override
    public String toString() {
        return "Pedido [id=" + id + ", data_pedido=" + data_pedido + ", status=" + status + ", pagamento=" + pagamento
                + ", usuario=" + getUsuario() + ", itens=" + itens + "]";
    }


    public PedidoItem add(PedidoItem item){
        itens.put(item, getQuantidade(item) + 1 );
        return item;
    }


    public Integer getQuantidade(PedidoItem item) {
        if(!itens.containsKey(item)){
            itens.put(item, 0);
        }
        return itens.get(item);
    }

    public BigDecimal getTotalItem(PedidoItem item){
        Integer quantidade = this.getQuantidade(item);
        BigDecimal quantidadeTotal = new BigDecimal(quantidade);
        BigDecimal preco = item.getProduto().getPreco();
        return quantidadeTotal.multiply(preco);

    }

    public BigDecimal getTotal(){
        BigDecimal total = BigDecimal.ZERO;
        for (PedidoItem    item : itens.keySet()) {
            total = total.add(getTotalItem(item));
        }

        return total;
    }


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }


    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    public String getPagamento() {
        return pagamento;
    }
    public void setPagamento(String pagamento) {
        this.pagamento = pagamento;
    }
    public Date getData_pedido() {
        return data_pedido;
    }
    public void setData_pedido(Date time) {
        this.data_pedido = time;
    }
    public Collection<PedidoItem> getItens() {
        return itens.keySet();
    }

    public int getQuantidade(){
        return itens.values().stream().reduce(0, (proximo, acumulador) -> (proximo + acumulador));

    }

    public void remover(Integer produtoId) {
        Produtos produto = new Produtos();
        produto.setId(produtoId);
        itens.remove(new PedidoItem(produto));
    }


    public Usuario getUsuario() {
        return usuario;
    }


    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }
}

que tem um relacionamento @ManyToOne com meu pedidoItem:

package br.com.rprvidros.models;

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

@Entity
public class PedidoItem {


    public PedidoItem(Produtos produto) {
        this.produto = produto;
    }

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

    @OneToOne
    private Produtos produto;

    @ManyToOne
    @JoinColumn(name = "pedido_id")
    private Pedido pedido;

    public Produtos getProduto() {
        return produto;
    }

    public void setProduto(Produtos produto) {
        this.produto = produto;
    }


    public Integer getId() {
        return id;
    }

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

    public Pedido getPedido() {
        return pedido;
    }

    public void setPedido(Pedido pedido) {
        this.pedido = pedido;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((pedido == null) ? 0 : pedido.hashCode());
        result = prime * result + ((produto == null) ? 0 : produto.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PedidoItem other = (PedidoItem) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (pedido == null) {
            if (other.pedido != null)
                return false;
        } else if (!pedido.equals(other.pedido))
            return false;
        if (produto == null) {
            if (other.produto != null)
                return false;
        } else if (!produto.equals(other.produto))
            return false;
        return true;
    }

}

meu método que estou usando para montar o pedido e também setar o pedidoItem:

@RequestMapping("/finaliza")
    public ModelAndView finalizaPedido(@AuthenticationPrincipal Usuario usuario){

        pedido.setUsuario(usuario);
        Date time = Calendar.getInstance().getTime();
        Collection<PedidoItem> itens = pedido.getItens();
        pedido.setData_pedido(time);
        pedido.setStatus("ABERTO");

        Pedido pedidoAdd = pDao.pedidoAdd(pedido);

        for (PedidoItem pedidoItem : itens) {
            pedidoItem.setPedido(pedidoAdd);
            pedidoItem.setProduto(pedidoItem.getProduto());
            itemDao.addPI(pedidoItem);
        }
        return new ModelAndView("rprvidros");
    }

eu estou setando o pedidoItem por um forEach pois meus pedidoItem estão em uma collections , mas eu estou passando, algum erro no relacionamento? pois eu tenho o mesmo para o usuario que estou setando em cima ele passa por essa linha sem problemas.

obrigado.

9 respostas

Parece que o erro tem a ver com a linha do?setPedido(pedido). Tem como conferir se pedido já tem id?

Boa noite Alberto estou persistindo o pedido nessa linha

```Pedido pedidoAdd = pDao.pedidoAdd(pedido);

```

Então na hora de setar ele na possui id não ?

Opa, então teoricamente esse pedidoAdd deveria ter um id já.. chegou a conferir?

eu fiz o teste, comentei a parte do ForEach :

//        for (PedidoItem pedidoItem : itens) {
//            pedidoItem.setPedido(pedidoAdd);
//            pedidoItem.setProduto(pedidoItem.getProduto());
//            itemDao.addPI(pedidoItem);
//        }

inserir so o pedido do banco e imprimi ele:

Pedido pedidoAdd = pDao.pedidoAdd(pedido);
        System.out.println(pedidoAdd);

ele imprimi isso:

Pedido [id=2, data_pedido=Thu Jul 27 11:46:52 BRT 2017, status=ABERTO, pagamento=null, usuario=Usuario [id=1, nome=gabriel, senha=$2a$10$8NX920kmB15QrxIt/4xmn.KMpLjNtt3fgeblm3vx2zQOiH2.VoxIC, email=gabriel_bartholo_batista@hotmail.com, emailAlternativo=gabriel_bartholo_batista@hotmail.com, telefone=2452345234, roles=ROLE_USUARIO], itens={br.com.rprvidros.models.PedidoItem@74f9=2}]
`

ele tem id como está ai, tem o id=2, mas ele da esse erro e não completa a inserção:

could not get a field value by reflection getter of br.com.rprvidros.models.PedidoItem.id; nested exception is org.hibernate.PropertyAccessException: could not get a field value by reflection getter of br.com.rprvidros.models.PedidoItem.id

pelo oq eu entendi ele não esta conseguindo um valor valido para o campo pedidoItem.id ?

mas eu nao estou mexendo no pedidoItem para persistir o pedido

Nunca vi a exception... agora estou mais base do chute... aquele relacionamento que você tem que é um Map, não pode ser uma lista convencional?

Acho que não alberto, estou usando como foi mostrado no curso de Spring mvc para controlar o carrinho de itens.

solução!

Opa Gabriel, acho que no curso ele não mapeia a entidade com um Map, não é que não seja possível... só é estranho... pq basicamente um pedido tem uma lista de itens...

Esse map aí é mantido dentro do carrinho da sessão do usuário, não no pedido.

no curso ele realmente não mapeia essa parte, pq não usado o BD, é tudo salvo em memória, mas eu estou fazendo no banco pra tentar chegar no mais real possível.

eu tambem pensei assim um pedido tem uma lista de itens, até levantei essa duvida aqui no fórum, no caso a pessoa me falou que seria mais simples eu ter uma tabela pedidoItem que se relaciona com minha tabela Pedido, como no cuso ele relaciona a o carrinho com o carrinhoItens dessa forma achei q seria assim o jeito mais fácil de seguir.

vc aconselha a mudar?

Alberto usei como vc disse um private List<PedidoItem> itens = new ArrayList<PedidoItem>(); refiz todos os métodos e agora funciona normalmente.

obrigado.