blaze-persistence icon indicating copy to clipboard operation
blaze-persistence copied to clipboard

saveFull throws exception on entity without mutable attributes

Open belovaf opened this issue 1 year ago • 2 comments

Description

Sometimes I need an entity view only for optimistic locking, because other changes are made by criteria queries.

@Entity
class MyEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Long? = null

  @Version
  val version: Short = 0

  // any other attributes
}

@UpdatableEntityView
@EntityView(MyEntity::class)
interface LockOnlyView {
    @get:IdMapping
    val id: Long
}
val view = evm.find(em, LockOnlyView::class.java, id)
// make changes with direct criteria queries (for test just do nothing)
evm.saveFull(em, view) // this line throws exception

Expected behavior

evm.saveFull should trigger version update with optimistic locking check. I think it should be like JPA LockModeType.OPTIMISTIC_FORCE_INCREMENT.

Actual behavior

Exception at: EntityViewUpdaterImpl line 713: int updated = query.executeUpdate();

Actual query is UPDATE MyEntity e SET e.version = :$$_version WHERE e.id = :_id AND e.version = :_$$_version. But binding parameters contain only 2 keys: _id, _$$_version. Key $$_version is missing.

Actual exception message: org.hibernate.QueryParameterException: No argument for named parameter ':$$_version'

Environment

Version: 1.6.11 JPA-Provider: Hibernate 6.4.1.Final DBMS: h2, postgresql, any db

belovaf avatar Jan 19 '24 22:01 belovaf

Hi and thanks for the report. I agree that this should work. In the meantime, you can workaround this by executing the HQL query manually.

beikov avatar Jan 23 '24 10:01 beikov

I implemented a workaround:

fun updateOptimisticForceIncrement(obj: Any) {
        require(obj is MutableStateTrackable) { "Can't update non-updatable entity views: $obj" }

        val hasVersion = em.metamodel.entity(obj.`$$_getJpaManagedClass`()).hasVersionAttribute()
        require(hasVersion) { "cannot force version increment on non-versioned entity" }

        if (obj.`$$_isDirty`()) {
            evm.save(em, obj)
        } else {
            executeOptimisticLockUpdate(obj)
        }
}

It would be very convenient to have such method in the library, because often I don't want to call saveFull it will do unnecessary column updates.

Jpa LockModeType.OPTIMISTIC_FORCE_INCREMENT for entity views is what I really need.

belovaf avatar Jan 23 '24 13:01 belovaf