带有 CascadeType.ALL 的 JPA OneToMany 不持久化子代

如何解决带有 CascadeType.ALL 的 JPA OneToMany 不持久化子代

大家早上好。我有一个简单的销售系统,用 Vaadin + Spring + Maven + MySQL 制作。

几乎一切正常,我唯一的问题是,在保存销售后,我可以保存客户的数据、付款方式和销售总额。但我无法保存产品、数量、单价和商品的总价值。

这是我在 git 上的存储库,供任何可以帮助我的人使用

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

我相信问题出在实体 Venda 或 View VendaView

在实体 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,null,null);
        produtos.add(produtoVenda);
    }

    private String valorTotalVenda;

}

我的视图如下所示:

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,5,"-").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();

    }
}

解决方法

在您的 Venda 类中,您正在 ProdutoVendido 的构造函数中使用 Venda.id。

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

我相信你应该让 orm 处理 id。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res