Kotlin Hibernate @ManyToOne MERGE 违反外键约束 (Postgres)
Kotlin Hibernate @ManyToOne MERGE violates foreign key constraint (Postgres)
我实现了一个@ModelToOne 关系,并想通过 Thymeleaf 使用下拉列表。我使用单独的公式来保存 PlaceEntities,并使用公式来保存 WorkEntities,其中可以从提到的下拉列表中选择适当的地点。当前的实现强制我添加一个 Place,否则将不会保留 WorkEntity。当我尝试在未从下拉列表中选择地点的情况下保存表单时,出现以下错误:
ERROR: insert or update on table "work" violates foreign key constraint "fklyi06ir16ujsbylbtf5k33rmv"
Detail: Key (place_of_premiere_id)=() is not present in table "place".
我已经尝试将“optional = true”条件(在任何情况下默认情况下都是 true)或 @JoinColumn(nullable = true) 添加到 @ManyToOne Side,但是 none 这些都有效。
保存带有选定地点的表单非常有效,但是如果我想保留一个没有 PlaceEntity 的 WorkEntity(这意味着外键列必须为空),我该如何做到这一点?
编辑:
我可以自己解决这个问题。错误来自模板第一个选项标签中的 th:value=""。它创建了一个不能持久化的零参数 Object 而不是 null。我在我的控制器中放置了一个 if 语句,这可能不是最优雅的方法,但我不知道如何在 Thymeleaf 中使 th:value= 可为空。
我的固定控制器:
@PostMapping(value = ["/addWork"])
fun addWork(@Validated work: Work?, bindingResult: BindingResult): String {
if (bindingResult.hasErrors()) {
print(bindingResult.allErrors)
}
work?.apply {
if (placeOfPremiere?.id == "") {
this.placeOfPremiere = null
}
}
workService.create(work!!)
return "editor/addWork"
}
所有实体的摘要 class:
@MappedSuperclass
abstract class Entity(
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
open var id: String?,
open var title: String?,
open var created: OffsetDateTime,
open var modified: OffsetDateTime
Child:
@Entity
@Table(name = "work")
class WorkEntity(
id: String? = null,
title: String? = null,
created: OffsetDateTime = OffsetDateTime.now(),
modified: OffsetDateTime = OffsetDateTime.now(),
var opus: String? = null,
var dateOfCreation: String? = null,
var dateOfPremiere: String? = null,
@JsonManagedReference
@ManyToOne(
fetch = FetchType.LAZY,
cascade = [CascadeType.MERGE]
)
var placeOfPremiere: PlaceEntity? = null,
...Other Properties...equals...hashcode...
Parent:
@Entity
@Table(name = "place")
class PlaceEntity(
id: String? = null,
title: String? = null,
created: OffsetDateTime = OffsetDateTime.now(),
modified: OffsetDateTime = OffsetDateTime.now(),
var name: String? = null,
var locality: String? = null,
var country: String? = null,
@Embedded
@AttributeOverrides(
AttributeOverride(name = "latitude", column = Column(name = "latitude")),
AttributeOverride(name = "longitude", column = Column(name = "longitude"))
)
var coordinates: CoordinatesEntity? = CoordinatesEntity(),
@JsonBackReference
@OneToMany(mappedBy = "placeOfPremiere")
var relatedWorks: MutableSet<WorkEntity>? = mutableSetOf()
...Other Properties...equals...hashcode...
我的 ThymeleafTemplate 的下拉菜单:
<div class="form-group">
<label for="places">Places</label>
<select th:field="*{placeOfPremiere.id}" class="form-control" id="places"
name="Place of Premiere">
<option th:value="">Select Places</option>
<option
th:each="place : ${places}"
th:value="${place.id}"
th:text="${place.title}">
</option>
</select>
<span th:if="${#fields.hasErrors('placeOfPremiere')}" th:errors {placeOfPremiere}"></span>
</div>
我想问题是 Work
实体指的是一个尚不存在的 Place
。要么将外键标记为 deferrable initially deferred
,要么确保调用 persist
或 merge
的顺序正确。
我实现了一个@ModelToOne 关系,并想通过 Thymeleaf 使用下拉列表。我使用单独的公式来保存 PlaceEntities,并使用公式来保存 WorkEntities,其中可以从提到的下拉列表中选择适当的地点。当前的实现强制我添加一个 Place,否则将不会保留 WorkEntity。当我尝试在未从下拉列表中选择地点的情况下保存表单时,出现以下错误:
ERROR: insert or update on table "work" violates foreign key constraint "fklyi06ir16ujsbylbtf5k33rmv" Detail: Key (place_of_premiere_id)=() is not present in table "place".
我已经尝试将“optional = true”条件(在任何情况下默认情况下都是 true)或 @JoinColumn(nullable = true) 添加到 @ManyToOne Side,但是 none 这些都有效。
保存带有选定地点的表单非常有效,但是如果我想保留一个没有 PlaceEntity 的 WorkEntity(这意味着外键列必须为空),我该如何做到这一点?
编辑: 我可以自己解决这个问题。错误来自模板第一个选项标签中的 th:value=""。它创建了一个不能持久化的零参数 Object 而不是 null。我在我的控制器中放置了一个 if 语句,这可能不是最优雅的方法,但我不知道如何在 Thymeleaf 中使 th:value= 可为空。
我的固定控制器:
@PostMapping(value = ["/addWork"])
fun addWork(@Validated work: Work?, bindingResult: BindingResult): String {
if (bindingResult.hasErrors()) {
print(bindingResult.allErrors)
}
work?.apply {
if (placeOfPremiere?.id == "") {
this.placeOfPremiere = null
}
}
workService.create(work!!)
return "editor/addWork"
}
所有实体的摘要 class:
@MappedSuperclass
abstract class Entity(
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
open var id: String?,
open var title: String?,
open var created: OffsetDateTime,
open var modified: OffsetDateTime
Child:
@Entity
@Table(name = "work")
class WorkEntity(
id: String? = null,
title: String? = null,
created: OffsetDateTime = OffsetDateTime.now(),
modified: OffsetDateTime = OffsetDateTime.now(),
var opus: String? = null,
var dateOfCreation: String? = null,
var dateOfPremiere: String? = null,
@JsonManagedReference
@ManyToOne(
fetch = FetchType.LAZY,
cascade = [CascadeType.MERGE]
)
var placeOfPremiere: PlaceEntity? = null,
...Other Properties...equals...hashcode...
Parent:
@Entity
@Table(name = "place")
class PlaceEntity(
id: String? = null,
title: String? = null,
created: OffsetDateTime = OffsetDateTime.now(),
modified: OffsetDateTime = OffsetDateTime.now(),
var name: String? = null,
var locality: String? = null,
var country: String? = null,
@Embedded
@AttributeOverrides(
AttributeOverride(name = "latitude", column = Column(name = "latitude")),
AttributeOverride(name = "longitude", column = Column(name = "longitude"))
)
var coordinates: CoordinatesEntity? = CoordinatesEntity(),
@JsonBackReference
@OneToMany(mappedBy = "placeOfPremiere")
var relatedWorks: MutableSet<WorkEntity>? = mutableSetOf()
...Other Properties...equals...hashcode...
我的 ThymeleafTemplate 的下拉菜单:
<div class="form-group">
<label for="places">Places</label>
<select th:field="*{placeOfPremiere.id}" class="form-control" id="places"
name="Place of Premiere">
<option th:value="">Select Places</option>
<option
th:each="place : ${places}"
th:value="${place.id}"
th:text="${place.title}">
</option>
</select>
<span th:if="${#fields.hasErrors('placeOfPremiere')}" th:errors {placeOfPremiere}"></span>
</div>
我想问题是 Work
实体指的是一个尚不存在的 Place
。要么将外键标记为 deferrable initially deferred
,要么确保调用 persist
或 merge
的顺序正确。