I implemented a @ModelToOne Relationship and would like to use a Dropdown List via Thymeleaf. I use a separate formular to persist PlaceEntities and a formular for WorkEntities where a appropriate Place can be selected from the mentioned dropdown list. The current implementation forces me to add a Place, otherwise a WorkEntity will not be persisted. When I try to save the form without having selected a Place from the dropdown list the following Error appears:
ERROR: insert or update on table "work" violates foreign key constraint "fklyi06ir16ujsbylbtf5k33rmv" Detail: Key (place_of_premiere_id)=() is not present in table "place".
I already tried to add the "optional = true" condition (which is true by default in any case) or @JoinColumn(nullable = true) to the @ManyToOne Side but none of these worked.
Saving the form with a selected Place works like a charm but how can I do this if I want to persist a WorkEntity without a PlaceEntity (which means that the foreignkey column must be null)?
EDIT: I could solve this problem by myself. The error came from the th:value="" in the first option tag of my template. Instead of null it creates a zero args Object of Place which cannot be persisted. I put an if statement in my controller which might be not the most elegant approach but I do not know how to make a th:value= nullable in Thymeleaf.
My fixed Controller:
@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"
}
Abstract class for all Entities:
@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...
The Dropdown Menu of my 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>