[英]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.