Hibernate/JPA OneToOne共享密钥,没有生成值



使用:SpringBoot、Kotlin和Hibernate/JPA、MariaDB(不认为重要(

我遇到了一些关于Hibernate/JPA的奇怪问题(但我希望Hibernate能处理我的问题(,下面的代码不起作用,我得到了这个错误:

java.sql.SQLException: Column 'book_id' cannot be null
Query is: insert into book_detail (pages, book_id) values (?, ?), parameters [48,<null>]

Book.kt

@Entity
data class Book(
@Id
val id: Int = 0,
val name: String? = null
) : Serializable {
@OneToOne(mappedBy = "book", cascade = [CascadeType.ALL])
var details: BookDetail? = null
}

BookDetails.kt

@Entity
@Table(name = "book_detail")
data class BookDetail(
@Column(name = "pages")
var pages: Int? = null,
@Id
@OneToOne
@JoinColumn(name = "book_id")
var book: Book? = null
) : Serializable

但是,如果我在Book.kt的主键上添加generatedValue,那么它将工作并持久化实体。

Book.kt

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int = 0

但我不想让Hibernate生成ID,当我在IDE中检查时,我可以看到所有实体都设置正确(Book<->BookDetails之间的链接似乎很好(

那么,为什么它使用自动生成的ID,而不是当我自己设置ID时?

用于持久化实体的代码:

val id = 2
val book = repo.findById(id).orElse(Book(id = id))
book.name = "Book B"
val details = BookDetail(48)
details.book = book
book.details = details
repo.save(book)

首先,ID不应该为null,因为这与ID的概念相矛盾。

我想你要找的是一个嵌入式ID:

@Embeddable
data class BookId(val value: Long) : Serializable
@Entity
data class Book(
@EmbeddedId
@AttributeOverride(name = "value", column = Column(name = "book_id"))
val id: BookId(0),
val name: String? = null
)

您可以通过创建一个BookId对象并将其传递给构造函数来设置ID:

val myBook = Book(BookId(42), "Moby Dick")

不要忘记为ID类实现AttributeConverter

@Converter
class BookIdConverter : AttributeConverter<BookId, Long> {
override fun convertToDatabaseColumn(bookId: BookId): Long = bookId.value
override fun convertToEntityAttribute(dbId: Long) = BookId(dbId)
}

最新更新