Merge pull request #12763 from thingsboard/fix/created-entity-version

Fix invalid entity version after creation
This commit is contained in:
Viacheslav Klimov 2025-02-27 12:50:15 +02:00 committed by GitHub
commit c210a23662
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 30 deletions

View File

@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -60,6 +61,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE; import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
@ -79,6 +81,8 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Autowired @Autowired
private DeviceProfileDao deviceProfileDao; private DeviceProfileDao deviceProfileDao;
static final String LWM2M_PROFILE_JSON = "{\"name\":\"lwm2m profile\",\"type\":\"DEFAULT\",\"image\":null,\"defaultQueueName\":null,\"transportType\":\"LWM2M\",\"provisionType\":\"DISABLED\",\"description\":\"\",\"profileData\":{\"configuration\":{\"type\":\"DEFAULT\"},\"transportConfiguration\":{\"observeAttr\":{\"observe\":[],\"attribute\":[],\"telemetry\":[\"/11_1.1/0/0\"],\"keyName\":{\"/11_1.1/0/0\":\"profileName\"},\"attributeLwm2m\":{}},\"bootstrap\":[{\"shortServerId\":123,\"bootstrapServerIs\":false,\"host\":\"0.0.0.0\",\"port\":5685,\"clientHoldOffTime\":1,\"serverPublicKey\":\"\",\"serverCertificate\":\"\",\"bootstrapServerAccountTimeout\":0,\"lifetime\":300,\"defaultMinPeriod\":1,\"notifIfDisabled\":true,\"binding\":\"U\",\"securityMode\":\"NO_SEC\"}],\"clientLwM2mSettings\":{\"clientOnlyObserveAfterConnect\":1,\"fwUpdateStrategy\":1,\"swUpdateStrategy\":1,\"powerMode\":\"DRX\",\"edrxCycle\":81000,\"psmActivityTimer\":10000,\"pagingTransmissionWindow\":10000,\"defaultObjectIDVer\":\"1.0\"},\"bootstrapServerUpdateEnable\":false,\"type\":\"LWM2M\"},\"alarms\":null,\"provisionConfiguration\":{\"type\":\"DISABLED\"}}}";
static class Config { static class Config {
@Bean @Bean
@Primary @Primary
@ -119,7 +123,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
Assert.assertNotNull(savedDeviceProfile.getId()); Assert.assertNotNull(savedDeviceProfile.getId());
Assert.assertTrue(savedDeviceProfile.getCreatedTime() > 0); Assert.assertTrue(savedDeviceProfile.getCreatedTime() > 0);
@ -135,7 +139,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
ActionType.ADDED); ActionType.ADDED);
savedDeviceProfile.setName("New device profile"); savedDeviceProfile.setName("New device profile");
doPost("/api/deviceProfile", savedDeviceProfile, DeviceProfile.class); saveDeviceProfile(savedDeviceProfile);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName()); Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName());
@ -162,7 +166,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testFindDeviceProfileById() throws Exception { public void testFindDeviceProfileById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertNotNull(foundDeviceProfile); Assert.assertNotNull(foundDeviceProfile);
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile); Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
@ -171,7 +175,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void whenGetDeviceProfileById_thenPermissionsAreChecked() throws Exception { public void whenGetDeviceProfileById_thenPermissionsAreChecked() throws Exception {
DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null); DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null);
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); deviceProfile = saveDeviceProfile(deviceProfile);
loginDifferentTenant(); loginDifferentTenant();
@ -183,7 +187,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testFindDeviceProfileInfoById() throws Exception { public void testFindDeviceProfileInfoById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/" + savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class); DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/" + savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class);
Assert.assertNotNull(foundDeviceProfileInfo); Assert.assertNotNull(foundDeviceProfileInfo);
Assert.assertEquals(savedDeviceProfile.getId(), foundDeviceProfileInfo.getId()); Assert.assertEquals(savedDeviceProfile.getId(), foundDeviceProfileInfo.getId());
@ -213,7 +217,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void whenGetDeviceProfileInfoById_thenPermissionsAreChecked() throws Exception { public void whenGetDeviceProfileInfoById_thenPermissionsAreChecked() throws Exception {
DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null); DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null);
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); deviceProfile = saveDeviceProfile(deviceProfile);
loginDifferentTenant(); loginDifferentTenant();
doGet("/api/deviceProfileInfo/" + deviceProfile.getId()) doGet("/api/deviceProfileInfo/" + deviceProfile.getId())
@ -235,7 +239,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testSetDefaultDeviceProfile() throws Exception { public void testSetDefaultDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -328,7 +332,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testChangeDeviceProfileTypeNull() throws Exception { public void testChangeDeviceProfileTypeNull() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -345,7 +349,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception { public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Device device = new Device(); Device device = new Device();
device.setName("Test device"); device.setName("Test device");
device.setType("default"); device.setType("default");
@ -367,7 +371,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testDeleteDeviceProfileWithExistingDevice() throws Exception { public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Device device = new Device(); Device device = new Device();
device.setName("Test device"); device.setName("Test device");
@ -419,7 +423,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
public void testSaveDeviceProfileWithFirmwareFromDifferentTenant() throws Exception { public void testSaveDeviceProfileWithFirmwareFromDifferentTenant() throws Exception {
loginDifferentTenant(); loginDifferentTenant();
DeviceProfile differentProfile = createDeviceProfile("Different profile"); DeviceProfile differentProfile = createDeviceProfile("Different profile");
differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class); differentProfile = saveDeviceProfile(differentProfile);
SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
firmwareInfo.setDeviceProfileId(differentProfile.getId()); firmwareInfo.setDeviceProfileId(differentProfile.getId());
firmwareInfo.setType(FIRMWARE); firmwareInfo.setType(FIRMWARE);
@ -441,7 +445,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
public void testSaveDeviceProfileWithSoftwareFromDifferentTenant() throws Exception { public void testSaveDeviceProfileWithSoftwareFromDifferentTenant() throws Exception {
loginDifferentTenant(); loginDifferentTenant();
DeviceProfile differentProfile = createDeviceProfile("Different profile"); DeviceProfile differentProfile = createDeviceProfile("Different profile");
differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class); differentProfile = saveDeviceProfile(differentProfile);
SaveOtaPackageInfoRequest softwareInfo = new SaveOtaPackageInfoRequest(); SaveOtaPackageInfoRequest softwareInfo = new SaveOtaPackageInfoRequest();
softwareInfo.setDeviceProfileId(differentProfile.getId()); softwareInfo.setDeviceProfileId(differentProfile.getId());
softwareInfo.setType(SOFTWARE); softwareInfo.setType(SOFTWARE);
@ -462,7 +466,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testDeleteDeviceProfile() throws Exception { public void testDeleteDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -495,7 +499,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
int cntEntity = 28; int cntEntity = 28;
for (int i = 0; i < cntEntity; i++) { for (int i = 0; i < cntEntity; i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile" + i); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile" + i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); deviceProfiles.add(saveDeviceProfile(deviceProfile));
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new DeviceProfile(), new DeviceProfile(), testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new DeviceProfile(), new DeviceProfile(),
@ -552,7 +556,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
for (int i = 0; i < 28; i++) { for (int i = 0; i < 28; i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile" + i); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile" + i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); deviceProfiles.add(saveDeviceProfile(deviceProfile));
} }
List<DeviceProfileInfo> loadedDeviceProfileInfos = new ArrayList<>(); List<DeviceProfileInfo> loadedDeviceProfileInfos = new ArrayList<>();
@ -961,7 +965,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
JsonTransportPayloadConfiguration jsonTransportPayloadConfiguration = new JsonTransportPayloadConfiguration(); JsonTransportPayloadConfiguration jsonTransportPayloadConfiguration = new JsonTransportPayloadConfiguration();
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(jsonTransportPayloadConfiguration, true); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(jsonTransportPayloadConfiguration, true);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT); Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT);
Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration); Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration);
@ -979,7 +983,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
"v1/devices/me/telemetry", "v1/devices/me/attributes", "v1/devices/me/subscribeattributes"); "v1/devices/me/telemetry", "v1/devices/me/attributes", "v1/devices/me/subscribeattributes");
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile",
mqttDeviceProfileTransportConfiguration); mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT); Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT);
Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration); Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration);
@ -997,7 +1001,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null); ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null);
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile); Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
@ -1036,14 +1040,14 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
@Test @Test
public void testDeleteDeviceProfileWithDeleteRelationsOk() throws Exception { public void testDeleteDeviceProfileWithDeleteRelationsOk() throws Exception {
DeviceProfileId deviceProfileId = savedDeviceProfile("DeviceProfile for Test WithRelationsOk").getId(); DeviceProfileId deviceProfileId = saveDeviceProfile("DeviceProfile for Test WithRelationsOk").getId();
testEntityDaoWithRelationsOk(savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId); testEntityDaoWithRelationsOk(savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId);
} }
@Ignore @Ignore
@Test @Test
public void testDeleteDeviceProfileExceptionWithRelationsTransactional() throws Exception { public void testDeleteDeviceProfileExceptionWithRelationsTransactional() throws Exception {
DeviceProfileId deviceProfileId = savedDeviceProfile("DeviceProfile for Test WithRelations Transactional Exception").getId(); DeviceProfileId deviceProfileId = saveDeviceProfile("DeviceProfile for Test WithRelations Transactional Exception").getId();
testEntityDaoWithRelationsTransactionalException(deviceProfileDao, savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId); testEntityDaoWithRelationsTransactionalException(deviceProfileDao, savedTenant.getId(), deviceProfileId, "/api/deviceProfile/" + deviceProfileId);
} }
@ -1103,8 +1107,36 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
Assert.assertEquals(count, deviceProfileNames.size()); Assert.assertEquals(count, deviceProfileNames.size());
} }
private DeviceProfile savedDeviceProfile(String name) { @Test
public void testSaveDeviceProfileWithOutdatedVersion() throws Exception {
DeviceProfile deviceProfile = JacksonUtil.fromString(LWM2M_PROFILE_JSON, DeviceProfile.class);
deviceProfile.setName("Device profile v1.0");
deviceProfile = saveDeviceProfile(deviceProfile);
assertThat(deviceProfile.getVersion()).isOne();
deviceProfile.setName("Device profile v2.0");
deviceProfile = saveDeviceProfile(deviceProfile);
assertThat(deviceProfile.getVersion()).isEqualTo(2);
deviceProfile.setName("Device profile v1.1");
deviceProfile.setVersion(1L);
String response = doPost("/api/deviceProfile", deviceProfile).andExpect(status().isConflict())
.andReturn().getResponse().getContentAsString();
assertThat(JacksonUtil.toJsonNode(response).get("message").asText())
.containsIgnoringCase("already changed by someone else");
deviceProfile.setVersion(null); // overriding entity
deviceProfile = saveDeviceProfile(deviceProfile);
assertThat(deviceProfile.getName()).isEqualTo("Device profile v1.1");
assertThat(deviceProfile.getVersion()).isEqualTo(3);
}
private DeviceProfile saveDeviceProfile(String name) {
DeviceProfile deviceProfile = createDeviceProfile(name); DeviceProfile deviceProfile = createDeviceProfile(name);
return saveDeviceProfile(deviceProfile);
}
private DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile) {
return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
} }

View File

@ -88,10 +88,10 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
boolean flushed = false; boolean flushed = false;
EntityManager entityManager = getEntityManager(); EntityManager entityManager = getEntityManager();
if (isNew) { if (isNew) {
entityManager.persist(entity);
if (entity instanceof HasVersion versionedEntity) { if (entity instanceof HasVersion versionedEntity) {
versionedEntity.setVersion(1L); versionedEntity.setVersion(1L);
} }
entityManager.persist(entity);
} else { } else {
if (entity instanceof HasVersion versionedEntity) { if (entity instanceof HasVersion versionedEntity) {
if (versionedEntity.getVersion() == null) { if (versionedEntity.getVersion() == null) {
@ -106,23 +106,25 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
} }
} }
versionedEntity = entityManager.merge(versionedEntity); versionedEntity = entityManager.merge(versionedEntity);
entity = (E) versionedEntity;
/* /*
* by default, Hibernate doesn't issue an update query and thus version increment * 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 * if the entity was not modified. to bypass this and always increment the version, we do it manually
* */ * */
versionedEntity.setVersion(versionedEntity.getVersion() + 1); versionedEntity.setVersion(versionedEntity.getVersion() + 1);
/*
* flushing and 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(versionedEntity);
flushed = true;
entity = (E) versionedEntity;
} else { } else {
entity = entityManager.merge(entity); entity = entityManager.merge(entity);
} }
} }
if (entity instanceof HasVersion versionedEntity) {
/*
* flushing and 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(versionedEntity);
flushed = true;
}
if (flush && !flushed) { if (flush && !flushed) {
entityManager.flush(); entityManager.flush();
} }