JPA OneToMany with CascadeType.ALL not persisting children



大家早上好。我有一个简单的销售系统,用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, 0, 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, 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();
}
}

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

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

我认为你应该让orm处理id。

最新更新