У меня есть торговые и адресные таблицы. у одного продавца может быть несколько адресов, а у одного адреса - один продавец (отношение один ко многим). Когда я добавляю значение продавца с адресом, я получаю эту ошибку. Как решить эту ошибку? Это ошибка.
{
"timestamp": 1554878673504,
"status": 500,
"error": "Internal Server Error",
"message": "could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/merchant-service/save-merchant"
}
Это мои входные значения:
{
"idNo": null,
"idType": null,
"emailId": "[email protected]",
"name": null,
"status": true,
"createdBy": null,
"modifiedBy": null,
"createdDate": null,
"modifiedDate": null,
"contacts": [
{"contactNo": "0766601122"}],
"addresses": [
{"line1": "manipay"},
{"line1": "suthumalai"}
]
}
это мой код в модели продавца:
@OneToMany(fetch = FetchType.LAZY,cascade = {CascadeType.ALL}, mappedBy = "merchant")
private Set<Address> addresses = new HashSet<Address>(
0);
это мой код в модели адреса:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "merchant_id", nullable = false)
// @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
// @Getter(onMethod = @__( @JsonIgnore))
// @Setter
private Merchant merchant;
это мой сервис:
public Merchant saveMerchant(Merchant merchant) {
merchant = merchantRepository.save(merchant);
return merchant;
}
@JBNizet, когда я добавляю продавца, я хочу добавить адреса к этому идентификатору продавца. У вас есть решение?
да. Установите мерчант в поле адресов: merchant.getAddresses().forEach(address -> address.setMerchant(merchant))
.
В нем говорится, что у вас есть ошибка нарушения ограничения, что означает, что вы могли установить любую переменную в объекте не равной нулю, и вы пытаетесь сохранить нулевое значение.
здесь идентификатор продавца не указан. Я знаю этот момент, но мой сценарий, когда я добавляю продавца в то же время, хочет добавить адреса в таблицу адресов с идентификатором продавца.
почему бы вам сначала не получить адреса, не сохранить их в таблице адресов, а затем использовать merchant.getAddresses.set(addresses)
I ваша модель продавца, вы установили cascade = {CascadeType.ALL}
для атрибута адреса. Это означает, что в этом случае, если вы хотите сохранить объект Merchant с некоторыми адресами, впадать в спячку проверит, существуют ли уже эти адреса; если нет, он создаст их раньше. Но в вашей модели адреса вы устанавливаете nullabel = false
атрибут продавца, что означает, что объект Address не может сохраняться без существующего продавца. Затем, когда впадать в спячку попытается сохранить продавца и найти адрес, который еще не сохранен, он попытается сохранить этот адрес раньше, он также найдет нулевой объект продавца, а затем выдаст это исключение org.hibernate.exception.ConstraintViolationException
.
Вы должны выбрать одно из этих предложений:
Удалите ограничение nullable = false
в атрибуте продавца в модели адреса. если вы это сделаете, адрес будет сохранен без продавца. Затем, когда вы продолжите, продавец впадать в спячку обновит адрес.
Измените cascade = {CascadeType.ALL}
на все остальные каскады, кроме PERSIST в атрибуте адресов модели Merchant. Если вы это сделаете, вы должны сохранить Merchant перед собой, а затем сохранить Address с существующим Merchant.
Можете ли вы изменить мой код, потому что я не мог понять ваш ответ.
Попробуйте это @JoinColumn(name = "merchant_id") вместо @JoinColumn(name = "merchant_id", nullable = false)
{ "timestamp": 1554885216731, "status": 500, "error": "Внутренняя ошибка сервера", "message": "не удалось выполнить оператор; SQL [n/a]; ограничение [null]; вложенное исключение - org. hibernate.exception.ConstraintViolationException: не удалось выполнить оператор", "path": "/merchant-service/save-merchant" }
в весеннем журнале загрузки: java.sql.SQLIntegrityConstraintViolationException: столбец «merchant_id» не может быть нулевым
Я уверен, что в таблице адресов полеmerchant_id не имеет нулевого ограничения. Вы также должны удалить его.
Я решил эту проблему. Я добавил этот ответ здесь.
В таблице продавца:
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}, mappedBy = "merchant")
private Set<Address> addresses = new HashSet<Address>(
0);
В таблице адресов:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "merchant_id")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Getter(onMethod = @__( @JsonIgnore))
@Setter
private Merchant merchant;
В сервисе:
public Merchant saveMerchant(Merchant merchant) {
merchant = merchantRepository.save(merchant);
Merchant finalMerchant = merchant;
merchant.getAddresses().forEach(address -> {
address.setMerchant(finalMerchant);
addressRepository.save(address);
});
return merchant;
}
Он отлично работает.
Не следует создавать нового продавца для каждого адреса. Вы должны указать уникального продавца в каждом адресе.
@JBNizet Вот я так и делаю.
Я даю один идентификатор продавца на все адреса.
Предполагается, что все адреса принадлежат одному и тому же продавцу. Итак, почему вы создаете продавца новый для каждого адреса. Просто установите один и тот же объект продавца на каждый адрес.
Это пустой объект продавца, и после добавления продавца я получаю этот идентификатор и устанавливаю идентификатор для объекта продавца и прикрепляю к address.setMerchant. Это работает для меня. если у вас есть какие-либо сомнения, я пошлю свой выход.
Сначала я добавляю продавца, а затем использую этот идентификатор для каждого создания адреса.
Работает, но излишне сложно и неэффективно, и неправильно, так как, повторюсь, на всех адресах должен стоять мерчант тоже самое: тот, который вы сохраняете при старте метода.
@JBNizet Я обновил этот ответ, пожалуйста, не могли бы вы его проверить?
Это гораздо лучше. Вы можете сделать это еще проще, настроив продавца на адреса перед сохранением продавца и удалив вызов addressRepository.save(address), поскольку у вас есть каскад, и сохранение продавца, таким образом, сохранит адреса.
Давайте продолжить обсуждение в чате.
Вы не опубликовали полную трассировку стека исключения, но я предполагаю, что у вас есть ненулевое ограничение для address.merchant_id, и поскольку ваш код никогда не устанавливает для address.merchant ненулевое значение перед вставкой продавца и своих адресов, Hibernate сохраняет значение null в Merchant_id, что приводит к нарушению ограничения.