Merge pull request #11466 from thingsboard/fix/versioned-entity
Fix entity's version incremented twice
This commit is contained in:
commit
0c15791c2e
@ -25,6 +25,7 @@ import jakarta.persistence.Enumerated;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.hibernate.annotations.JdbcType;
|
import org.hibernate.annotations.JdbcType;
|
||||||
import org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType;
|
import org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
@ -48,6 +49,7 @@ import java.util.UUID;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = ModelConstants.DEVICE_PROFILE_TABLE_NAME)
|
@Table(name = ModelConstants.DEVICE_PROFILE_TABLE_NAME)
|
||||||
|
@ToString(callSuper = true)
|
||||||
public final class DeviceProfileEntity extends BaseVersionedEntity<DeviceProfile> {
|
public final class DeviceProfileEntity extends BaseVersionedEntity<DeviceProfile> {
|
||||||
|
|
||||||
@Column(name = ModelConstants.DEVICE_PROFILE_TENANT_ID_PROPERTY)
|
@Column(name = ModelConstants.DEVICE_PROFILE_TENANT_ID_PROPERTY)
|
||||||
|
|||||||
@ -58,6 +58,10 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public D save(TenantId tenantId, D domain) {
|
public D save(TenantId tenantId, D domain) {
|
||||||
|
return save(tenantId, domain, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private D save(TenantId tenantId, D domain, boolean flush) {
|
||||||
E entity;
|
E entity;
|
||||||
try {
|
try {
|
||||||
entity = getEntityClass().getConstructor(domain.getClass()).newInstance(domain);
|
entity = getEntityClass().getConstructor(domain.getClass()).newInstance(domain);
|
||||||
@ -73,14 +77,15 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
entity.setCreatedTime(Uuids.unixTimestamp(uuid));
|
entity.setCreatedTime(Uuids.unixTimestamp(uuid));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
entity = doSave(entity, isNew);
|
entity = doSave(entity, isNew, flush);
|
||||||
} catch (OptimisticLockException e) {
|
} catch (OptimisticLockException e) {
|
||||||
throw new EntityVersionMismatchException((getEntityType() != null ? getEntityType().getNormalName() : "Entity") + " was already changed by someone else", e);
|
throw new EntityVersionMismatchException((getEntityType() != null ? getEntityType().getNormalName() : "Entity") + " was already changed by someone else", e);
|
||||||
}
|
}
|
||||||
return DaoUtil.getData(entity);
|
return DaoUtil.getData(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected E doSave(E entity, boolean isNew) {
|
protected E doSave(E entity, boolean isNew, boolean flush) {
|
||||||
|
boolean flushed = false;
|
||||||
EntityManager entityManager = getEntityManager();
|
EntityManager entityManager = getEntityManager();
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
if (entity instanceof HasVersion versionedEntity) {
|
if (entity instanceof HasVersion versionedEntity) {
|
||||||
@ -94,24 +99,32 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
|
|||||||
if (existingEntity != null) {
|
if (existingEntity != null) {
|
||||||
versionedEntity.setVersion(existingEntity.getVersion()); // manually resetting the version to latest to allow force overwrite of the entity
|
versionedEntity.setVersion(existingEntity.getVersion()); // manually resetting the version to latest to allow force overwrite of the entity
|
||||||
} else {
|
} else {
|
||||||
return doSave(entity, true);
|
return doSave(entity, true, flush);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entity = entityManager.merge(entity);
|
entity = entityManager.merge(entity);
|
||||||
|
/*
|
||||||
|
* flushing so that the query is executed right away and the version is incremented,
|
||||||
|
* then removing the entity from the persistence context so that it is not affected
|
||||||
|
* by next flushes (e.g. when a transaction is committed) to avoid double version increment
|
||||||
|
* */
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
|
entityManager.detach(entity);
|
||||||
|
flushed = true;
|
||||||
} else {
|
} else {
|
||||||
entity = entityManager.merge(entity);
|
entity = entityManager.merge(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flush && !flushed) {
|
||||||
|
entityManager.flush();
|
||||||
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public D saveAndFlush(TenantId tenantId, D domain) {
|
public D saveAndFlush(TenantId tenantId, D domain) {
|
||||||
D d = save(tenantId, domain);
|
return save(tenantId, domain, true);
|
||||||
getRepository().flush();
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -22,9 +22,9 @@ import org.thingsboard.server.dao.util.SqlDao;
|
|||||||
public abstract class JpaPartitionedAbstractDao<E extends BaseEntity<D>, D> extends JpaAbstractDao<E, D> {
|
public abstract class JpaPartitionedAbstractDao<E extends BaseEntity<D>, D> extends JpaAbstractDao<E, D> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected E doSave(E entity, boolean isNew) {
|
protected E doSave(E entity, boolean isNew, boolean flush) {
|
||||||
createPartition(entity);
|
createPartition(entity);
|
||||||
return super.doSave(entity, isNew);
|
return super.doSave(entity, isNew, flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void createPartition(E entity);
|
public abstract void createPartition(E entity);
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.thingsboard.server.common.data.EntityInfo;
|
import org.thingsboard.server.common.data.EntityInfo;
|
||||||
import org.thingsboard.server.common.data.EntityType;
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||||
@ -58,14 +57,6 @@ public class JpaAssetProfileDao extends JpaAbstractDao<AssetProfileEntity, Asset
|
|||||||
return assetProfileRepository.findAssetProfileInfoById(assetProfileId);
|
return assetProfileRepository.findAssetProfileInfoById(assetProfileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
|
||||||
public AssetProfile saveAndFlush(TenantId tenantId, AssetProfile assetProfile) {
|
|
||||||
AssetProfile result = save(tenantId, assetProfile);
|
|
||||||
assetProfileRepository.flush();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageData<AssetProfile> findAssetProfiles(TenantId tenantId, PageLink pageLink) {
|
public PageData<AssetProfile> findAssetProfiles(TenantId tenantId, PageLink pageLink) {
|
||||||
return DaoUtil.toPageData(
|
return DaoUtil.toPageData(
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
import org.thingsboard.server.common.data.DeviceProfileInfo;
|
import org.thingsboard.server.common.data.DeviceProfileInfo;
|
||||||
import org.thingsboard.server.common.data.DeviceTransportType;
|
import org.thingsboard.server.common.data.DeviceTransportType;
|
||||||
@ -62,14 +61,6 @@ public class JpaDeviceProfileDao extends JpaAbstractDao<DeviceProfileEntity, Dev
|
|||||||
return deviceProfileRepository.findDeviceProfileInfoById(deviceProfileId);
|
return deviceProfileRepository.findDeviceProfileInfoById(deviceProfileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
|
||||||
public DeviceProfile saveAndFlush(TenantId tenantId, DeviceProfile deviceProfile) {
|
|
||||||
DeviceProfile result = save(tenantId, deviceProfile);
|
|
||||||
deviceProfileRepository.flush();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageData<DeviceProfile> findDeviceProfiles(TenantId tenantId, PageLink pageLink) {
|
public PageData<DeviceProfile> findDeviceProfiles(TenantId tenantId, PageLink pageLink) {
|
||||||
return DaoUtil.toPageData(
|
return DaoUtil.toPageData(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user