3
At the moment, I’m having a problem with mapping @OneToMany
/@ManyToOne
in my application. I would like it when I persist my entity Sale
automatically save the sale items in single shot.
@Entity
@Table(name = "sale")
public class Sale implements Serializable {
private static final long serialVersionUID = -3857608619547245492L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "company", nullable = false)
private Long company;
@JsonIgnore
@OneToMany(mappedBy = "sale", cascade = CascadeType.ALL, orphanRemoval = true)
private List<SaleItem> saleItems = new ArrayList<>();
public Sale() {
}
public void addSaleItem(SaleItem saleItem) {
getSaleItems().add(saleItem);
saleItem.setSale(this);
}
//****************************Getters and Setters****************************
}
@Entity
@Table(name = "sale_item")
public class SaleItem implements Serializable {
private static final long serialVersionUID = 1016354254590870341L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "company", nullable = false)
private Long company;
@Column(name = "description", nullable = false)
private String description;
@Column(name = "amount", nullable = false)
private Double amount;
@Column(name = "price", nullable = false)
private Double price;
@ManyToOne(fetch = FetchType.LAZY)
private Sale sale;
public SaleItem() {
}
//**************************** SEM SALE Getters e Setters ****************************
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof SaleItem))
return false;
return id != null && id.equals(((SaleItem) o).getId());
}
@Override
public int hashCode() {
return 31;
}
@Override
public String toString() {
return "SaleItem [id=" + id + ", company=" + company + ", product=" + product + ", created=" + created
+ ", updated=" + updated + ", description=" + description + ", amount=" + amount + ", price=" + price
+ ", discount=" + discount + ", user=" + user + ", unit=" + unit + ", sale=" + sale + "]";
}
}
//*********************** My Controller ***********************
/**
* Create Sale
*
* @param sale
* @param result
* @return ResponseEntity<Response<SaleDto>>
* @throws ParseException
*/
@PostMapping
public ResponseEntity<Response<SaleDto>> create(@Valid @RequestBody SaleDto saleDto, BindingResult result)
throws ParseException {
log.info("Creating sale: {}", saleDto.toString());
Response<SaleDto> response = new Response<SaleDto>();
validateSale(saleDto, result);
if (result.hasErrors()) {
log.error("Error - invalid information for Sale: {}", result.getAllErrors());
result.getAllErrors().forEach(error -> response.getErrors().add(error.getDefaultMessage()));
return ResponseEntity.badRequest().body(response);
}
response.setData(this.convertSaleDto(this.nova(saleDto, result)));
return ResponseEntity.ok(response);
}
private Sale nova(SaleDto saleDto, BindingResult result) throws ParseException {
Sale sale = new Sale();
sale.setCompany(saleDto.getCompany());
sale.setUser(saleDto.getUser());
sale.setType(TypeSales.valueOf(saleDto.getType()));
sale.setDescription(saleDto.getDescription());
sale.setValue(saleDto.getValue());
sale.setSubValue(saleDto.getSubValue());
sale.setDiscount(saleDto.getDiscount());
for (int i = 0; i < saleDto.getItems().size(); i++) {
SaleItem saleItem = new SaleItem();
saleItem.setCompany(saleDto.getCompany());
saleItem.setUser(saleDto.getUser());
saleItem.setProduct(saleDto.getItems().get(i).getProduct());
saleItem.setAmount(saleDto.getItems().get(i).getAmount());
saleItem.setPrice(saleDto.getItems().get(i).getPrice());
saleItem.setDescription(saleDto.getItems().get(i).getDescription());
saleItem.setDiscount(saleDto.getItems().get(i).getDiscount());
saleItem.setUnit(saleDto.getItems().get(i).getUnit());
sale.addSaleItem(saleItem);
}
return this.saleService.persist(sale);
}
//**************************My Service**************
/**
* Persist a sale
*
* @param Sale
* @return Sale
*/
Sale persist(Sale sale);
//******************My impl***********************
@Transactional
public Sale persist(Sale sale) {
log.info("Persisting sale {}", sale);
return this.saleRepository.save(sale);
}
The problem that is only saving the entity Sale
leaving items blank at all times.
So using this suggestion I end up having the error that was not filled sale_id. 2020-02-09 00:50:55.734 ERROR 17036 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.Sqlexceptionhelper : Field 'sale_id' doesn’t have a default value
– mPissolato
You kept the id attribute in the classes ? The ids are being auto-incremented ?
– brendonmiranda
I kept the ID’s but I took the Sale class of entity item.
– mPissolato
The property Mapped by tbm has been removed?
– brendonmiranda
Yes, I removed the only doubt I had if I should declare in the entity Saleitem the "sale_id" ?
– mPissolato
No need. It may be that your changes are not being reflected in the bank and may require re-creation of the bank. If it still makes sense for you to take a look at this link, it has a very similar problem to yours and that’s how it solved https://stackoverflow.com/questions/804514/hibernate-field-id-doesnt-have-a-default-value
– brendonmiranda
It makes sense the unidirectional mapping which makes no sense that at any time I identify for the items who is the father. I just read the article you referred me and was held the father identification in the items.
– mPissolato
In the article indicated in the answer, it exemplifies on top of a bidirectional, promoting some improvements. In the case of unidirectional something like this should work for you: https://reinaldoc.wordpress.com/2011/11/25/jpa-onetomany-unidirectionl-join-comjoin-columncolumn/
– brendonmiranda