1

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
}
Aleks Azen
  • 11
  • 1
  • After messing around with this the culprit seems to be this annotation `@MapsId("munchId")` for some reason having this specified forces Cascading when merging a `Swipe` or a `Munch`. I've removed that and the `munchId` field from the embeddedId and everything works as expected. Would love if someone could explain why – Aleks Azen Sep 07 '20 at 22:31

1 Answers1

0

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