#java #hibernate #spring-boot
#java #спящий режим #spring-boot
Вопрос:
У меня есть торговые и адресные таблицы. у одного продавца может быть несколько адресов, а у одного адреса есть один продавец (отношение «один ко многим»).При добавлении значения продавца с адресом я получаю эту ошибку. Как решить эту ошибку? Это ошибка.
{
"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@gmail.com",
"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;
}
Комментарии:
1. Вы не опубликовали полную трассировку стека исключения, но я предполагаю, что у вас есть ненулевое ограничение для address.merchant_id , и поскольку ваш код никогда не устанавливает address.merchant в ненулевое значение перед вставкой merchant и его адресов, Hibernate сохраняет null в merchant_id, вызываянарушение ограничений.
2. @JBNizet когда я одновременно добавляю продавца, я хочу добавить адреса к этому идентификатору продавца. Есть ли у вас какое-либо решение?
3. ДА. Установите поле merchant для адресов:
merchant.getAddresses().forEach(address -> address.setMerchant(merchant))
.
Ответ №1:
В вашей торговой модели вы устанавливаете cascade = {CascadeType.ALL}
атрибут addresses . Это означает, что в этом случае, если вы хотите сохранить объект Merchant с некоторыми адресами, режим гибернации проверит, существуют ли эти адреса; если нет, он создаст их раньше. Но в вашей модели адресов вы устанавливаете nullabel = false
атрибут merchant, который означает, что объект Address не может сохраняться без существующего продавца. Затем, когда спящий режим пытается сохранить продавца и найти адрес, который еще не сохранен, он пытается сохранить этот адрес раньше, он также находит нулевой объект продавца, а затем выдает это исключение org.hibernate.exception.ConstraintViolationException
.
Вы должны выбрать одно из этих предложений:
-
Удалите
nullable = false
ограничение в атрибуте продавца в адресной модели. если вы это сделаете, адрес будет сохранен без продавца. Затем, когда вы сохраняете спящий режим продавца, он обновит адрес. -
Измените
cascade = {CascadeType.ALL}
на все другие каскады, кроме СОХРАНЕНИЯ в атрибуте addresses торговой модели. Если вы это сделаете, вы должны сохранить продавца перед собой, а затем сохранить адрес у существующего продавца.
Комментарии:
1. Можете ли вы изменить мой код, потому что я не смог понять ваш ответ.
2. Попробуйте этот @JoinColumn(name = «merchant_id») вместо @JoinColumn(name = «merchant_id», nullable = false)
3. { «отметка времени»: 1554885216731, «статус»: 500, «ошибка»: «Внутренняя ошибка сервера», «сообщение»: «не удалось выполнить инструкцию; SQL [n / a]; ограничение [null]; вложенным исключением является org.hibernate.exception. ConstraintViolationException: не удалось выполнить оператор», «path»: «/ merchant-service /save-merchant» }
4. в журнале загрузки spring: java.sql.SQLIntegrityConstraintViolationException: столбец ‘merchant_id’ не может быть нулевым
5. Я уверен, что в таблице адресов поле merchant_id не имеет ограничения null. Вы также должны удалить его.
Ответ №2:
В таблице Merchent:
@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;
}
Он отлично работает.
Комментарии:
1. Вы не должны создавать нового продавца для каждого адреса. Вы должны установить уникального продавца в каждом адресе.
2. @JBNizet Здесь я делаю вот так.
3. Я даю один идентификатор продавца на все адреса.
4. Предполагается, что все адреса имеют одного и того же продавца. Итак, почему вы создаете нового продавца для каждого адреса. Просто установите один и тот же объект merchant на каждый адрес.
5. Это пустой объект merchant, и после добавления merchant я получаю этот идентификатор и устанавливаю идентификатор в объект merchant и прикрепляю к address.setMerchant. Это работает для меня. если у вас есть какие-либо сомнения, я отправлю свой ответ.
Ответ №3:
В нем говорится, что у вас ошибка нарушения ограничений, что означает, что вы, возможно, установили для любой переменной в сущности значение not null, и вы пытаетесь сохранить значение null.
Комментарии:
1. здесь идентификатор продавца не задан. Я знаю этот момент, но мой сценарий, когда при добавлении продавца одновременно адреса хотят добавляться в таблицу адресов с идентификатором продавца.
2. почему бы вам сначала не получить адреса, сохранить их в таблице адресов, а затем использовать
merchant.getAddresses.set(addresses)