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 lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
import org.hibernate.annotations.JdbcType;
 | 
			
		||||
import org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
@ -48,6 +49,7 @@ import java.util.UUID;
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = ModelConstants.DEVICE_PROFILE_TABLE_NAME)
 | 
			
		||||
@ToString(callSuper = true)
 | 
			
		||||
public final class DeviceProfileEntity extends BaseVersionedEntity<DeviceProfile> {
 | 
			
		||||
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_PROFILE_TENANT_ID_PROPERTY)
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,10 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional
 | 
			
		||||
    public D save(TenantId tenantId, D domain) {
 | 
			
		||||
        return save(tenantId, domain, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private D save(TenantId tenantId, D domain, boolean flush) {
 | 
			
		||||
        E entity;
 | 
			
		||||
        try {
 | 
			
		||||
            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));
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            entity = doSave(entity, isNew);
 | 
			
		||||
            entity = doSave(entity, isNew, flush);
 | 
			
		||||
        } catch (OptimisticLockException e) {
 | 
			
		||||
            throw new EntityVersionMismatchException((getEntityType() != null ? getEntityType().getNormalName() : "Entity") + " was already changed by someone else", e);
 | 
			
		||||
        }
 | 
			
		||||
        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();
 | 
			
		||||
        if (isNew) {
 | 
			
		||||
            if (entity instanceof HasVersion versionedEntity) {
 | 
			
		||||
@ -94,24 +99,32 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
 | 
			
		||||
                    if (existingEntity != null) {
 | 
			
		||||
                        versionedEntity.setVersion(existingEntity.getVersion()); // manually resetting the version to latest to allow force overwrite of the entity
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return doSave(entity, true);
 | 
			
		||||
                        return doSave(entity, true, flush);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                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.detach(entity);
 | 
			
		||||
                flushed = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                entity = entityManager.merge(entity);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (flush && !flushed) {
 | 
			
		||||
            entityManager.flush();
 | 
			
		||||
        }
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional
 | 
			
		||||
    public D saveAndFlush(TenantId tenantId, D domain) {
 | 
			
		||||
        D d = save(tenantId, domain);
 | 
			
		||||
        getRepository().flush();
 | 
			
		||||
        return d;
 | 
			
		||||
        return save(tenantId, domain, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected E doSave(E entity, boolean isNew) {
 | 
			
		||||
    protected E doSave(E entity, boolean isNew, boolean flush) {
 | 
			
		||||
        createPartition(entity);
 | 
			
		||||
        return super.doSave(entity, isNew);
 | 
			
		||||
        return super.doSave(entity, isNew, flush);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.asset.AssetProfile;
 | 
			
		||||
@ -58,14 +57,6 @@ public class JpaAssetProfileDao extends JpaAbstractDao<AssetProfileEntity, Asset
 | 
			
		||||
        return assetProfileRepository.findAssetProfileInfoById(assetProfileId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Transactional
 | 
			
		||||
    @Override
 | 
			
		||||
    public AssetProfile saveAndFlush(TenantId tenantId, AssetProfile assetProfile) {
 | 
			
		||||
        AssetProfile result = save(tenantId, assetProfile);
 | 
			
		||||
        assetProfileRepository.flush();
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageData<AssetProfile> findAssetProfiles(TenantId tenantId, PageLink pageLink) {
 | 
			
		||||
        return DaoUtil.toPageData(
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.data.domain.PageRequest;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceProfile;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceProfileInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceTransportType;
 | 
			
		||||
@ -62,14 +61,6 @@ public class JpaDeviceProfileDao extends JpaAbstractDao<DeviceProfileEntity, Dev
 | 
			
		||||
        return deviceProfileRepository.findDeviceProfileInfoById(deviceProfileId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Transactional
 | 
			
		||||
    @Override
 | 
			
		||||
    public DeviceProfile saveAndFlush(TenantId tenantId, DeviceProfile deviceProfile) {
 | 
			
		||||
        DeviceProfile result = save(tenantId, deviceProfile);
 | 
			
		||||
        deviceProfileRepository.flush();
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageData<DeviceProfile> findDeviceProfiles(TenantId tenantId, PageLink pageLink) {
 | 
			
		||||
        return DaoUtil.toPageData(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user