Fixes for Hibernate 6 support
This commit is contained in:
parent
5e566d9d95
commit
24ff462b31
@ -21,14 +21,13 @@ import jakarta.persistence.Id;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.annotations.UuidGenerator;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.sql.IdGenerator;
|
||||
import org.thingsboard.server.dao.sql.IdGenerator.GeneratedId;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -46,7 +45,7 @@ public abstract class BaseSqlEntity<D> implements BaseEntity<D> {
|
||||
|
||||
@Id
|
||||
@Column(name = ModelConstants.ID_PROPERTY, columnDefinition = "uuid")
|
||||
@UuidGenerator(style = UuidGenerator.Style.AUTO, algorithm = IdGenerator.class)
|
||||
@GeneratedId
|
||||
protected UUID id;
|
||||
|
||||
@Column(name = ModelConstants.CREATED_TIME_PROPERTY, updatable = false)
|
||||
|
||||
@ -17,17 +17,44 @@ package org.thingsboard.server.dao.sql;
|
||||
|
||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.annotations.IdGeneratorType;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.uuid.UuidValueGenerator;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.EventTypeSets;
|
||||
import org.thingsboard.server.dao.model.BaseEntity;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.EnumSet;
|
||||
|
||||
@Slf4j
|
||||
public class IdGenerator implements UuidValueGenerator {
|
||||
public class IdGenerator implements BeforeExecutionGenerator {
|
||||
|
||||
@Override
|
||||
public UUID generateUuid(SharedSessionContractImplementor session) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
if (owner instanceof BaseEntity<?> entity && entity.getUuid() != null) {
|
||||
return entity.getUuid();
|
||||
}
|
||||
return Uuids.timeBased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAssignedIdentifiers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return EventTypeSets.INSERT_ONLY;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@IdGeneratorType(IdGenerator.class)
|
||||
public @interface GeneratedId {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,12 +15,14 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.sql;
|
||||
|
||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.OptimisticLockException;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@ -69,6 +71,14 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
boolean isNew = entity.getUuid() == null;
|
||||
if (isNew) {
|
||||
entity.setCreatedTime(System.currentTimeMillis());
|
||||
} else {
|
||||
if (entity.getCreatedTime() == 0) {
|
||||
if (entity.getUuid().version() == 1) {
|
||||
entity.setCreatedTime(Uuids.unixTimestamp(entity.getUuid()));
|
||||
} else {
|
||||
entity.setCreatedTime(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
entity = doSave(entity, isNew, flush);
|
||||
@ -82,33 +92,9 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
boolean flushed = false;
|
||||
EntityManager entityManager = getEntityManager();
|
||||
if (isNew) {
|
||||
entityManager.persist(entity);
|
||||
if (entity instanceof HasVersion versionedEntity) {
|
||||
versionedEntity.setVersion(1L);
|
||||
}
|
||||
entity = create(entity);
|
||||
} else {
|
||||
if (entity instanceof HasVersion versionedEntity) {
|
||||
if (versionedEntity.getVersion() == null) {
|
||||
HasVersion existingEntity = entityManager.find(versionedEntity.getClass(), entity.getUuid());
|
||||
if (existingEntity != null) {
|
||||
/*
|
||||
* manually resetting the version to latest to allow force overwrite of the entity
|
||||
* */
|
||||
versionedEntity.setVersion(existingEntity.getVersion());
|
||||
} else {
|
||||
return doSave(entity, true, flush);
|
||||
}
|
||||
}
|
||||
versionedEntity = entityManager.merge(versionedEntity);
|
||||
entity = (E) versionedEntity;
|
||||
/*
|
||||
* by default, Hibernate doesn't issue an update query and thus version increment
|
||||
* if the entity was not modified. to bypass this and always increment the version, we do it manually
|
||||
* */
|
||||
versionedEntity.setVersion(versionedEntity.getVersion() + 1);
|
||||
} else {
|
||||
entity = entityManager.merge(entity);
|
||||
}
|
||||
entity = update(entity);
|
||||
}
|
||||
if (entity instanceof HasVersion versionedEntity) {
|
||||
/*
|
||||
@ -125,6 +111,53 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
||||
return entity;
|
||||
}
|
||||
|
||||
private E create(E entity) {
|
||||
if (entity instanceof HasVersion versionedEntity) {
|
||||
versionedEntity.setVersion(1L);
|
||||
}
|
||||
if (entity.getUuid() == null) {
|
||||
getEntityManager().persist(entity);
|
||||
} else {
|
||||
if (entity instanceof HasVersion) {
|
||||
/*
|
||||
* Hibernate 6 does not allow creating versioned entities with preset IDs.
|
||||
* Bypassing by calling the underlying session directly
|
||||
* */
|
||||
Session session = getEntityManager().unwrap(Session.class);
|
||||
session.save(entity);
|
||||
} else {
|
||||
entity = getEntityManager().merge(entity);
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private E update(E entity) {
|
||||
if (entity instanceof HasVersion versionedEntity) {
|
||||
if (versionedEntity.getVersion() == null) {
|
||||
HasVersion existingEntity = entityManager.find(versionedEntity.getClass(), entity.getUuid());
|
||||
if (existingEntity != null) {
|
||||
/*
|
||||
* manually resetting the version to latest to allow force overwriting of the entity
|
||||
* */
|
||||
versionedEntity.setVersion(existingEntity.getVersion());
|
||||
} else {
|
||||
return create(entity);
|
||||
}
|
||||
}
|
||||
versionedEntity = entityManager.merge(versionedEntity);
|
||||
entity = (E) versionedEntity;
|
||||
/*
|
||||
* by default, Hibernate doesn't issue an update query and thus version increment
|
||||
* if the entity was not modified. to bypass this and always increment the version, we do it manually
|
||||
* */
|
||||
versionedEntity.setVersion(versionedEntity.getVersion() + 1);
|
||||
} else {
|
||||
entity = entityManager.merge(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public D saveAndFlush(TenantId tenantId, D domain) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user