简体   繁体   English

JPA OneToMany 与 CascadeType.ALL 不持久的孩子

[英]JPA OneToMany with CascadeType.ALL not persisting children

Good morning everybody.大家早上好。 I have a simple sales system, made in Vaadin + Spring + Maven + MySQL.我有一个简单的销售系统,在 Vaadin + Spring + Maven + MySQL 制造。

Almost everything is working perfectly, my only problem is that, after saving a sale, I can save the customer's data, the payment method and the total amount of the sale.几乎一切都运行良好,我唯一的问题是,保存销售后,我可以保存客户的数据、付款方式和销售总额。 But I can't save the products, the quantities, the unit value and the total value of the item.但我无法保存商品、数量、单位价值和商品的总价值。

Here is my repository on git for anyone who can help me这是我在 git 上的存储库,供任何可以帮助我的人使用

https://github.com/fjdesenvolvimento/Sistema-Vendas-Vaadin https://github.com/fjdesenvolvimento/Sistema-Vendas-Vaadin

The problem, I believe, is in the entity Venda or View VendaView我相信问题出在实体 Venda 或 View VendaView

in the entity Venda the code looks like this:在实体 Venda 中,代码如下所示:

package br.com.fjsistemas.backend;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

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

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Data
@Entity
public class Venda {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private LocalDate dataVenda = LocalDate.now();

    @ManyToOne
    private Cliente cliente;

    @ManyToOne
    private FormaDePagamento formaDePagamento;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<ProdutoVendido> produtos = new ArrayList<>();

    public void addProduto(Produto produto) {
        ProdutoVendido produtoVenda = new ProdutoVendido(id, this, produto, 0, null, null);
        produtos.add(produtoVenda);
    }

    private String valorTotalVenda;

}

my View looks like this:我的视图如下所示:

package br.com.fjsistemas.compraVenda;

import java.text.NumberFormat;
import java.text.ParseException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.textfieldformatter.CustomStringBlockFormatter;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.PropertyId;
import com.vaadin.flow.data.renderer.LocalDateRenderer;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

import br.com.fjsistemas.backend.Cliente;
import br.com.fjsistemas.backend.FormaDePagamento;
import br.com.fjsistemas.backend.Produto;
import br.com.fjsistemas.backend.ProdutoVendido;
import br.com.fjsistemas.backend.Venda;
import br.com.fjsistemas.main.MainView;
import br.com.fjsistemas.repository.ClienteRepository;
import br.com.fjsistemas.repository.FormaDePagamentoRepository;
import br.com.fjsistemas.repository.ProdutoRepository;
import br.com.fjsistemas.service.VendaService;

@Route(value = "venda-view", layout = MainView.class)
@PageTitle("Lançamento de Vendas")
public class VendaView extends VerticalLayout {

    private static final long serialVersionUID = 1L;

    private HorizontalLayout hltVenda = new HorizontalLayout();
    Grid<Venda> grdVenda = new Grid<>(Venda.class, false);

    private HorizontalLayout hltBarraBotoes = new HorizontalLayout();
    Button btnNovo = new Button("Novo");
    Button btnAlterar = new Button("Alterar");
    Button btnExcluir = new Button("Excluir");

    private Dialog dlgJanela = new Dialog();

    Div superior = new Div();
    Div centro = new Div();
    Div inferior = new Div();

    HorizontalLayout primeiraLinhaDivSuperior = new HorizontalLayout();
    HorizontalLayout segundaLinhaDivSuperior = new HorizontalLayout();
    HorizontalLayout adicionarProdutos = new HorizontalLayout();

    @PropertyId("dataVenda")
    private DatePicker txtDataVenda = new DatePicker("Data Venda");

    @PropertyId("cliente")
    private ComboBox<Cliente> txtNomeCliente = new ComboBox<>("Cliente");

    @PropertyId("telefone")
    private TextField txtTelefone = new TextField("Telefone");

    @PropertyId("celular")
    private TextField txtCelular = new TextField("Celular");

    @PropertyId("endereco")
    private TextField txtEndereco = new TextField("Endereço");

    @PropertyId("numero")
    private TextField txtNumero = new TextField("Nº");

    @PropertyId("bairro")
    private TextField txtBairro = new TextField("Bairro");

    @PropertyId("cidade")
    TextField txtCidade = new TextField("Cidade");

    @PropertyId("estado")
    TextField txtEstado = new TextField("Estado");

    @PropertyId("formaDePagamento")
    private ComboBox<FormaDePagamento> txtFormasPagamento = new ComboBox<>("Formas de Pagamento");

    @PropertyId("valorTotalVenda")
    private TextField campoSomaValores = new TextField();

    private HorizontalLayout htlDlgBarraBotoes = new HorizontalLayout();
    private Button btnSalvar = new Button("Salvar");
    private Button btnFechar = new Button("Fechar");
    private Button btnAdicionarItem = new Button("+ Item");

    @Autowired
    VendaService vendaService;

    @Autowired
    ClienteRepository clienteRepository;

    @Autowired
    FormaDePagamentoRepository formaDePagamentoRepository;

    @Autowired
    ProdutoRepository produtoRepository;

    private List<Venda> listaVendas;
    private List<TextField> valores = new ArrayList<>();
    private Venda venda = new Venda();

    Binder<Venda> binderVenda = new Binder<>(Venda.class);

    public VendaView() {

    }

    @PostConstruct
    public void init() {
        configuraTela();

    }

    private void configuraTela() {

        setMargin(false);
        setPadding(false);

        configuraHltVenda();
        configuraFltBarraBotoes();
        configuraDlgJanela();
        populaGrdVenda();
        configuraBinder();

        add(hltVenda, hltBarraBotoes);
    }

    private void configuraFltBarraBotoes() {

        btnNovo.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnNovo.addClickListener(e -> {
            novoClick();
        });

        btnAlterar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnAlterar.addClickListener(e -> {
            alterarClick();
        });

        btnExcluir.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnExcluir.addClickListener(e -> {
            excluirClick();
        });

        hltBarraBotoes.add(btnNovo, btnAlterar, btnExcluir);
    }

    private void excluirClick() {

        if (venda != null) {
            listaVendas.remove(venda);
            vendaService.delete(venda);
            atualizaGrdVenda();
        }
    }

    private void configuraHltVenda() {
        hltVenda.setWidthFull();
        configuraGrdVenda();
        hltVenda.add(grdVenda);
    }

    private void configuraGrdVenda() {
        grdVenda.setHeight("820px");
        grdVenda.setWidthFull();

        grdVenda.addColumn(Venda::getId).setHeader("ID:").setAutoWidth(true);

        grdVenda.addColumn(new LocalDateRenderer<>(Venda::getDataVenda, DateTimeFormatter.ofPattern("dd/MM/yyy")))
                .setHeader("Data Venda").setAutoWidth(true);

        grdVenda.addColumn(venda -> venda.getCliente().getNome()).setHeader("Nome:").setAutoWidth(true)
                .setKey("cliente.nome");

        grdVenda.addColumn(Venda::getValorTotalVenda).setHeader("Valor Total:").setAutoWidth(true)
                .setKey("valorTotalVenda");

        grdVenda.addColumn(venda -> venda.getFormaDePagamento().getFormaDePagamento()).setHeader("Forma de Pagamento")
                .setAutoWidth(true).setKey("formaDePagamento");

        grdVenda.addThemeVariants(GridVariant.LUMO_COMPACT, GridVariant.LUMO_COLUMN_BORDERS);

        grdVenda.getColumns().forEach(col -> col.setAutoWidth(true).setSortable(true).setResizable(true));

        grdVenda.addItemClickListener(e -> {
            venda = e.getItem();
        });

        grdVenda.addItemDoubleClickListener(event -> {
            if (venda != null) {
                binderVenda.readBean(venda);
                dlgJanela.open();
                montarListaProdutos(venda.getProdutos());

            }
        });

    }

    private void configuraDlgJanela() {

        dlgJanela.setHeightFull();
        dlgJanela.setWidthFull();
        dlgJanela.setCloseOnEsc(false);
        dlgJanela.setCloseOnOutsideClick(false);

        superior.setHeight("170px");
        superior.setWidthFull();

        txtNomeCliente.setWidth("350px");
        txtNomeCliente.setLabel("Nome Cliente");

        txtNomeCliente.setItemLabelGenerator(cliente -> {
            if (cliente == null || cliente.getNome() == null) {
                return " ";

            } else {
                return cliente.getNome();
            }
        });

        List<Cliente> listaDeClientes = clienteRepository.findAll();

        txtNomeCliente.setItems(listaDeClientes);
        txtNomeCliente.addValueChangeListener(event -> {
            if (event.getValue() == null || event.getValue().getFone() == null) {
                txtTelefone.setValue(" ");
            } else {
                txtTelefone.setValue(event.getValue().getFone());
            }
            if (event.getValue() == null || event.getValue().getCelular() == null) {
                txtCelular.setValue(" ");
            } else {
                txtCelular.setValue(event.getValue().getCelular());
            }
            if (event.getValue() == null || event.getValue().getEndereco() == null) {
                txtEndereco.setValue(" ");
            } else {
                txtEndereco.setValue(event.getValue().getEndereco());
            }
            if (event.getValue() == null || event.getValue().getNumero() == null) {
                txtNumero.setValue(" ");
            } else {
                txtNumero.setValue(event.getValue().getNumero());
            }
            if (event.getValue() == null || event.getValue().getBairro() == null) {
                txtBairro.setValue(" ");
            } else {
                txtBairro.setValue(event.getValue().getBairro());
            }
            if (event.getValue() == null || event.getValue().getCidade() == null) {
                txtCidade.setValue(" ");
            } else {
                txtCidade.setValue(event.getValue().getCidade());
            }
            if (event.getValue() == null || event.getValue().getEstado() == null) {
                txtEstado.setValue(" ");
            } else {
                txtEstado.setValue(event.getValue().getEstado());
            }

        });

        new CustomStringBlockFormatter.Builder().blocks(0, 2, 4, 4).delimiters("(", ")", "-").numeric().build()
                .extend(txtTelefone);

        new CustomStringBlockFormatter.Builder().blocks(0, 2, 5, 4).delimiters("(", ")", "-").numeric().build()
                .extend(txtCelular);

        primeiraLinhaDivSuperior.add(txtDataVenda, txtNomeCliente, txtTelefone, txtCelular, txtEndereco, txtNumero,
                txtBairro, txtCidade);

        txtNumero.setWidth("140px");

        txtFormasPagamento.setLabel("Formas de Pagamento");

        List<FormaDePagamento> listaPagamento = formaDePagamentoRepository.findAll();
        txtFormasPagamento.setItemLabelGenerator(FormaDePagamento::getFormaDePagamento);
        txtFormasPagamento.setItems(listaPagamento);

        segundaLinhaDivSuperior.add(txtEstado, txtFormasPagamento);
        superior.add(primeiraLinhaDivSuperior, segundaLinhaDivSuperior);

        centro.setHeight("660px");
        centro.getStyle().set("border-style", "ridge");
        centro.getStyle().set("overflow-y", "scroll");
        centro.setWidthFull();

        btnSalvar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnSalvar.getStyle().set("margin-top", "0em");
        btnSalvar.getStyle().set("margin-left", "1em");
        btnSalvar.addClickListener(e -> {
            salvarClick();

        });

        btnFechar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnFechar.getStyle().set("margin-top", "0em");
        btnFechar.addClickListener(e -> {
            dlgJanela.close();
            limparCampos();
        });

        btnAdicionarItem.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnAdicionarItem.getStyle().set("margin-top", "0em");
        btnAdicionarItem.addClickListener(e -> {
            adicionaProduto();
        });

        Label text = new Label("Valor Total");
        text.getElement().getStyle().set("fontWeight", "bold");
        text.getStyle().set("margin-top", "0.8em");
        text.getStyle().set("margin-left", "2em");
        text.getStyle().set("text-align", "center");
        campoSomaValores.getStyle().set("margin-top", "0em");
        campoSomaValores.getStyle().set("margin-right", "0.2em");
        campoSomaValores.setWidth("30em");

        htlDlgBarraBotoes.add(btnSalvar, btnFechar, btnAdicionarItem, text, campoSomaValores);

        inferior.getStyle().set("margin-top", "0px");
        inferior.setHeight("45px");
        inferior.setWidthFull();
        inferior.add(htlDlgBarraBotoes);

        dlgJanela.add(superior, centro, inferior);

    }

    private void montarListaProdutos(List<ProdutoVendido> produtosVendidos) {
        HorizontalLayout adicionarProdutos = new HorizontalLayout();

        for (ProdutoVendido pv : produtosVendidos) {
            adicionarProdutos.add(new TextField(pv.getProduto().getNome()));
            
        }

        centro.add(adicionarProdutos);
    }

    private void salvarClick() {

        venda = binderVenda.getBean();

        boolean adicionarLista = venda.getId() == null ? true : false;

        vendaService.create(venda);

        if (adicionarLista) {
            listaVendas.add(venda);

        }
        atualizaGrdVenda();
        novaVenda();
        txtNomeCliente.focus();

        binderVenda.setBean(venda);

        if (adicionarLista) {

            dlgJanela.close();
        }
    }

    private void populaGrdVenda() {

        listaVendas = vendaService.read();
        atualizaGrdVenda();
    }

    private void atualizaGrdVenda() {
        grdVenda.setItems(listaVendas);
    }

    private void configuraBinder() {

        binderVenda.bindInstanceFields(this);

    }

    private void novoClick() {

        novaVenda();
        binderVenda.setBean(venda);

        dlgJanela.open();
        txtNomeCliente.focus();
    }

    private void alterarClick() {

        if (venda != null) {
            binderVenda.setBean(venda);

            dlgJanela.open();

        }
    }

    private void adicionaProduto() {

        ComboBox<Produto> txtProdutos = new ComboBox<>();

        NumberField txtQuantidade = new NumberField("Quantidade");

        TextField txtValorUnitario = new TextField("Valor Unitário");

        TextField txtValorTotalItem = new TextField("Valor Total Item");

        txtProdutos.setWidth("370px");
        txtProdutos.setLabel("Produtos");
        List<Produto> listaDeProdutos = produtoRepository.findAll();
        txtProdutos.setItemLabelGenerator(Produto::getNome);
        txtProdutos.setItems(listaDeProdutos);
        txtProdutos.addValueChangeListener(event -> {

            NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("pt", "BR"));
            try {

                txtValorUnitario.setValue(formatter.format(event.getValue().getValor()));

            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // ==========================================================================================================================

        txtQuantidade.setHasControls(true);
        txtQuantidade.setValue(null);
        txtQuantidade.setMin(1);

        txtQuantidade.addValueChangeListener(event -> {

            NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("pt", "BR"));
            double valorTotal = 0;

            try {
                valorTotal = formatter.parse(txtValorUnitario.getValue()).doubleValue() * txtQuantidade.getValue();
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            txtValorTotalItem.setValue(formatter.format(valorTotal));

            double soma = 0;// interna
            for (TextField tf : valores) {
                try {
                    soma += formatter.parse(tf.getValue()).doubleValue();

                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            campoSomaValores.setValue(formatter.format(soma));// externa

        });

        adicionarProdutos = new HorizontalLayout();
        adicionarProdutos.add(txtProdutos, txtQuantidade, txtValorUnitario, txtValorTotalItem);
        centro.add(adicionarProdutos);
        valores.add(txtValorTotalItem);
        venda.addProduto(txtProdutos.getValue());
    }

    private void limparCampos() {
        centro.removeAll();
    }

    private void novaVenda() {
        venda = new Venda();
        venda.setCliente(null);
        venda.setFormaDePagamento(null);
        dlgJanela.close();

    }
}

in your Venda class you are using the Venda.id in the constructor of ProdutoVendido.在您的 Venda class 中,您正在使用 ProdutoVendido 的构造函数中的 Venda.id。

public void addProduto(Produto produto) {
    ProdutoVendido produtoVenda = new ProdutoVendido(id, this, produto, 0, null, null);
    produtos.add(produtoVenda);
}

I believe you should let the orm deal with ids.我相信您应该让 orm 处理 id。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM