I'm running into the following exception when I'm trying to persist new swipe
objects:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: org.munch.database.models.bunch.Munch
Here is the code I am executing:
databaseExecutor.executeAndRollbackOnFailure { entityManager ->
munch.swipes.forEach {
if (it.swipeIdKey.munchId != null) {
entityManager.persist(it)
} else if (it.updated) {
entityManager.merge(it)
}
}
entityManager.transaction.commit()
}
I've also pasted my entities below for reference.
When entityManager.persist(it)
is called, the above error is thrown. It is for some reason trying to persist the OneToMany
side of the entity as well which will not work. I've made sure that the CascadeTypes
arrays are empty for both so by my understanding only the Swipe
that I call entityManager.persist()
on should be written to the db.
If I replace persist
with merge
the operation succeeds but the merge causes hibernate to generate an additional select
for the Munch
and also a select
for the Swipe
which are unnecessary operations. The merge does not however seem to cascade the update operation to the Munch
it only does the 2 select statements and 1 insert.
To recap:
Hibernate seems to be cascading the Persist
operation when it shouldn't. A solution is to use merge
instead but using persist
should result only in 1 insert
where as merge
results in 2 selects + 1 insert
I'm out of ideas other than executing native queries to insert/update but I'd like to avoid that if possible.
Here are my entities:
Munch
@Entity
@TypeDefs(
TypeDef(
name = "list-array",
typeClass = ListArrayType::class
)
)
data class Munch(
@Column
val name: String,
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "munch",
)
val swipes: MutableList<Swipe> = mutableListOf(),
) {
@Id
@GenericGenerator(name = "generator", strategy = "uuid")
@GeneratedValue(generator = "generator")
lateinit var munchId: String
fun addSwipe(swipe: Swipe) {
swipes.add(swipe)
swipe.munch = this
}
}
Swipe
@Entity
data class Swipe(
@EmbeddedId
val swipeIdKey: SwipeIdKey,
@Column(nullable = true)
val liked: Boolean,
) : Serializable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "munchId")
@MapsId("munchId")
lateinit var munch: Munch
@Transient
var updated = false
SwipeIdKey
@Embeddable
class SwipeIdKey : Serializable {
@Column(nullable = false)
lateinit var restaurantId: String
@Column(nullable = true)
lateinit var userId: String
@Column(nullable = true)
var munchId: String? = null
}
That happens because you are trying to persist and object that doesn't exist so you should use the CascadeType.PERSIST or persist the SwipeIdKey object first