У меня есть отношение OneToMany для покупки к сведениям о покупке. Объект Purchase содержит основные сведения, а объект PurchaseDetails содержит список приобретенного товара. Я хочу добиться того, чтобы при сохранении данных в таблице покупок (родительский) список приобретенного товара также автоматически сохранялся в таблице PurchaseDetail (дочерний).
2019-07-19 13:05:53.581 WARN 8868 --- [nio-8060-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1048, SQLState: 23000 2019-07-19 13:05:53.581 ERROR 8868 --- [nio-8060-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : Column 'purchaseId' cannot be null
Покупка.java
@Entity
@Table(name = "purchase")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Purchase {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "purchaseId")
private BigInteger purchaseId;
@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "accountId", nullable = false)
private Account account;
@JsonBackReference
@OneToMany(mappedBy = "purchase",fetch=FetchType.LAZY,cascade = CascadeType.PERSIST)
private List<PurchaseDetails> purchaseDetails = new ArrayList<PurchaseDetails>();
private Date purchaseDate;
private String name;
private String address;
private String whatsapp;
private String payStatus;
private int creditDays;
private Float loading;
private BigInteger purchaseAmount;
private BigInteger receivedAmount;
private String remarks;
private Date creation;
private Date lastedit;
private Boolean isDeleted;
@PrePersist
protected void onCreate() {
creation = new Date();
lastedit = new Date();
isDeleted = false;
}
}
PurchaseDetails.java
@Entity
@Table(name = "purchaseDetails")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class PurchaseDetails {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private BigInteger purchaseDetailId;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Purchase.class)
@JoinColumn(name = "purchaseId", referencedColumnName = "purchaseId", nullable = false)
// @MapsId(value = "purchaseId")
private Purchase purchase;
@OneToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "itemId", nullable = false)
private Item item;
private Float quantity;
private Float rate;
private Float rateGST;
private Float subTotal;
private Float subTotalGST;
private Date creation;
private Date lastedit;
private Boolean isDeleted;
@PrePersist
protected void onCreate() {
creation = new Date();
lastedit = new Date();
isDeleted = false;
}
}
PurchaseService.java
@Service
public class PurchaseService {
@Autowired PurchaseRepository purchaseRepository;
public boolean newPurchase(Purchase purchase, StringResponseDTO response)
{
if (isValidPurchaseData(purchase))
{
System.out.println("Service: "+purchase.toString());
purchase.setPurchaseDetails(purchase.getPurchaseDetails());
purchaseRepository.save(purchase);
response.setMessage("Purchase of "+ purchase.getName() + " is added successfuly");
return true;
}
else
{
response.setMessage("Please Provide Valid Data");
return false;
}
}
}
JSON для ввода от Postman(значения предназначены только для тестирования, поэтому игнорируйте промежуточные итоги и т. д.)
{
"purchaseDate":"2019-07-18T08:37:41.000+0000",
"name":"PersonName",
"address":"Besides xyz Hotel, NH - 5, India",
"whatsapp":"1234567899",
"payStatus":"Paid",
"creditDays":"0",
"purchaseAmount":"2600",
"receivedAmount":"2600",
"loading":"100",
"remarks":"Not Any",
"purchaseDetails":[
{
"quantity":"523.6",
"rate":"67",
"rateGST":"70",
"subTotal":"35081",
"subTotalGST":"36652",
"item":{
"itemId":"14"
}
},
{
"quantity":"222.6",
"rate":"67",
"rateGST":"70",
"subTotal":"35081",
"subTotalGST":"36652",
"item":{
"itemId":"16"
}
}],
"account":{
"accountId":"4"
}
}
🤔 А знаете ли вы, что...
Java поддерживает множество протоколов, включая HTTP, FTP и многое другое.
Вы создали двунаправленную связь с родителем и потомками. Если вы хотите сохранить родителя и его дочерние элементы с помощью каскада, вам также необходимо установить родительский элемент для ваших детей, иначе у вас будет ошибка. Пожалуйста попробуйте :
for (PurchaseDetail purchaseDetail : purchase.getPurchaseDetails()) {
purchaseDetail.setPurchase(purchase);
}
purchase.setPurchaseDetails(purchase.getPurchaseDetails());
purchaseRepository.save(purchase);
у вас есть много отношений между Purchase и PurchaseDetails, тогда вы должны передать идентификатор покупки в PurchaseDetails, чтобы установить связь, таким образом:
1. В сервисном слое вы должны сначала добавить покупку без настройки PurchaseDetails
2. добавьте все сведения о покупке с той же покупкой, которая была добавлена на шаге 1.
@Service
public class PurchaseService {
@Autowired
PurchaseRepository purchaseRepository;
@Autowired
PurchaseDetailsRepository purchaseDetailsRepository;
public boolean newPurchase(Purchase purchase, StringResponseDTO response)
{
if (!isValidPurchaseData(purchase))
{
System.out.println("Service: "+purchase.toString());
//yo should have all PurchaseDetails in a list pay attention this list not null
List<PurchaseDetails> purchaseDetails=purchase.getPurchaseDetails();
//step 1
purchase=purchaseRepository.save(purchase);
response.setMessage("Purchase of "+ purchase.getName() + " is added successfuly");
for(PurchaseDetails adddetail:purchaseDetails){
//step 2
adddetail.setPurchase(purchase);
purchaseDetailsRepository.save(adddetail);
}
return true;
}
else
{
response.setMessage("Please Provide Valid Data");
return false;
}
}
}