我有兩個物體:Book 和 Page。書可以有很多頁。
@Entity(name = "book")
@RegisterForReflection
internal data class Book (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val bookId: Long? = null,
@OneToMany(mappedBy = "book", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
val pages: MutableSet<Page> = mutableSetOf(),
)
@Entity(name = "page")
@RegisterForReflection
internal data class Page(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val pageId: Long? = null,
@ManyToOne(fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
@JsonIgnore
var book: Book? = Book(),
)
兩個物體都在資料庫中保存和創建。但是,如果我嘗試獲取 Book,我會得到LazyInitializationException. 盡管我嘗試使用 Mutiny.fetch 或使用 LEFT JOIN FETCH 來獲取它,但它總是會拋出相同的錯誤。在我堅持/獲取的方式之下:
顯示代碼片段
@ApplicationScoped
internal class BookRepo : PanacheRepository<Book> {
fun getBook(bookId: Long): Uni<Book> {
return findById(bookId)
.call { it -> Mutiny.fetch(it.pages) }
.map {
it ?: throw RuntimeException("Not Found")
}
}
fun persistBook(book: Book): Uni<Book> {
return Panache.withTransaction {
persist(book)
}
}
}
@ApplicationScoped
internal class PageRepo : PanacheRepository<Page> {
fun persistPage(page: Page, bookId: Long): Uni<Page> {
return Panache.withTransaction {
getSession().chain { s ->
val book = s.getReference(Book::class.java, bookId)
page.book = book
persist(page)
}
}
}
}

我究竟做錯了什么?我用這個小例子創建了一個 repo,有一系列 CURL 請求來重現錯誤(請檢查自述檔案)。
uj5u.com熱心網友回復:
問題是物體的默認等于和哈希碼包括關聯。
因此,當您運行第一個選擇查詢時,如果在您獲取關聯之前呼叫它們,則會導致錯誤。
您需要將物體更改為:
@Entity(name = "page")
internal data class Page(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val pageId: Long? = null,
@ManyToOne(fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
@JsonIgnore
var book: Book? = null,
){
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Page
if (pageId != other.pageId) return false
return true
}
override fun hashCode(): Int {
return pageId?.hashCode() ?: 0
}
}
package org.acme
import org.hibernate.annotations.Fetch
import org.hibernate.annotations.FetchMode
import javax.persistence.*
@Entity(name = "book")
internal data class Book (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val bookId: Long? = null,
@OneToMany(mappedBy = "book", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
var pages: MutableSet<Page> = mutableSetOf(),
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Book
if (bookId != other.bookId) return false
return true
}
override fun hashCode(): Int {
return bookId?.hashCode() ?: 0
}
}
通常,您不應包含識別符號,但在此簡單示例中沒有其他欄位。Hibernate ORM 檔案有一段關于如何為物體實作哈希碼和等于,應該給你一個更好的解釋。
我注意到的另外幾件事:
- 我認為您不需要添加
@RegisterForReflection. 這僅在特定情況下有用,這不應該是其中之一。 - 多對一關聯通常用 null 初始化。那是因為您可以使用空檢查來檢查關聯是否存在。我懷疑它也可能導致錯誤,因為您正在關聯一個新的非托管物件。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/532387.html
