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

atualizando entidade ao invés de criar outra

No meu projeto eu crio um cliente e para cada cliente existem x produtos, porem quando crio o segundo produto, ao invés de ele ser inserido no banco de dados, o primeiro produto é atualizado com as informações do segundo

public class ProdutoDao {

    @PersistenceContext
    private EntityManager manager;

    @Autowired
    private MovimentacaoDao movimentacaoDao;

    public void persist(Produto produto) {
        if (produto.getId() == null) {
            manager.persist(produto);
        }
        else {
            manager.merge(produto);
        }
    }
@Controller
@RequestMapping("/produtos")
public class ProdutoController {

    @Autowired
    private ClienteDao clienteDao;

    @Autowired
    private ProdutoDao produtoDao;

    @RequestMapping(value = "/{id}/form")
    public ModelAndView form(@PathVariable Integer id) {
        ModelAndView modelAndView = new ModelAndView("produtos/form");
        Cliente cliente = clienteDao.getCliente(id);
        modelAndView.addObject("cliente", cliente);
        return modelAndView;
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.POST)
    public ModelAndView gravarProduto(@Valid Produto produto, BindingResult result, @PathVariable Integer id) {

        if (result.hasErrors()) {
            return form(id);
        } else {
            Cliente cliente = clienteDao.getCliente(id);
            produto.setCliente(cliente);
            produtoDao.persist(produto);

            return new ModelAndView("redirect:/produtos/{id}");
        }

    }
@Entity
public class Cliente {

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

    @NotEmpty(message = "Insira um nome")
    private String nome;

    @OneToMany(mappedBy = "cliente")
    private List<Produto> produtos;
@Entity
public class Produto {

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

    @NotEmpty(message = "Insira uma referência")
    private String referencia;
    @NotEmpty(message = "Insira uma descrição")
    private String descricao;
    @NotEmpty(message = "Insira um tamanho")
    private String tamanho;
    @NotEmpty(message = "Insira uma cor")
    private String cor;
    @NotNull(message = "Somente número maior ou igual a 0")
    private Integer estoque;

    @ManyToOne
    private Cliente cliente;
4 respostas

O jsp do formulario do produto

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<%@ page isELIgnored="false"%>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
    href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<title>Controle de Estoque</title>
</head>
<body class="container p-3 mb-2 bg-secondary text-white vh-100 wh-100">
    <form class="form-group"
        action="/controle-de-estoque/produtos/${cliente.id}" method="POST">
        <div>
            <label>Referência:</label> <form:errors path="produto.referencia" class="text-warning"/> <input  class="form-control" type="text"
                name="referencia" value="${produto.referencia}">

        </div>
        <div>
            <label>Descrição:</label> <form:errors path="produto.descricao" class="text-warning"/>
            <input class="form-control" name="descricao"  value="${produto.descricao}"/>

        </div>
        <div>
            <label>Tamanho:</label> <form:errors path="produto.tamanho" class="text-warning"/> <input class="form-control" type="text"
                name="tamanho" value="${produto.tamanho}">

        </div>
        <div>
            <label>cor:</label> <form:errors path="produto.cor" class="text-warning"/><input class="form-control" type="text"
                name="cor" value="${produto.cor}">

        </div>
        <div>
            <label>Estoque:</label> <form:errors path="produto.estoque" class="text-warning"/> <input class="form-control" type="text"
                name="estoque" value="${produto.estoque}">

        </div>

        <button class="btn btn-success mr-1 mt-2" type="submit">Cadastrar</button>
        <a class="btn btn-primary ml-1 mt-2 "
            href="http://localhost:8080/controle-de-estoque/produtos/${cliente.id}">Voltar
            aos Produtos</a>
    </form>
    <footer class="fixed-bottom text-light bg-dark">
        <div class="text-left  float-left">© Nicolas Brunaldi de
            Oliveira, 2019</div>
        <div class="text-right">Versão 1.0.0</div>
    </footer>
</body>
</html>

Caso eu deixe o método persist() do ProdutoDao assim:

@Repository
@Transactional
public class ProdutoDao {

    @PersistenceContext
    private EntityManager manager;

    @Autowired
    private MovimentacaoDao movimentacaoDao;

    public void persist(Produto produto) {
            manager.persist(produto);

Acontece este erro na pagina ao dar submit:

HTTP Status 500 – Internal Server Error
Type Exception Report

Message Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.ykz.controledeestoque.models.Produto

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.ykz.controledeestoque.models.Produto
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.ykz.controledeestoque.models.Produto
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)

O problema é que você está sempre passando um ID ao invés de passar NULL para que o Hibernate entenda que você quer cadastrar um produto novo.

Para resolver esse problema ao invés de usar o .persiste você pode usar o .merge

solução!

Obrigado Otávio em relação ao erro de: detached entity passed to persist era só usar o merge no lugar de persist.

Agora em relação a atualizar ao invés de inserir eu resolvi trocando o @GeneratedValue da classe Produto

@Entity
public class Produto {

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

troquei de IDENTITY para SEQUENCE

@Entity
public class Produto {

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