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