Hibernate Relationship: столбец «purchaseId» не может быть нулевым

У меня есть отношение 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 и многое другое.


2 432
2

Ответы:

Решено

Вы создали двунаправленную связь с родителем и потомками. Если вы хотите сохранить родителя и его дочерние элементы с помощью каскада, вам также необходимо установить родительский элемент для ваших детей, иначе у вас будет ошибка. Пожалуйста попробуйте :

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;
    }
}
}