Support multiple updates of one resource in a transaction (#2050)

* Support multiple updates of one resource in a transaction

* Test update

* Add changelog

* Test fix
This commit is contained in:
James Agnew 2020-08-25 05:55:54 -04:00 committed by GitHub
parent 969a20d9e8
commit 437e81fc65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 10 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 2050
title: An issue was fixed where multiple JPA server updates to the same resource within the same
database transaction would fail with a database constraint error.

View File

@ -1057,7 +1057,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
entity.setLanguage(((IAnyResource) theResource).getLanguageElement().getValue());
}
newParams.setParamsOn(entity);
newParams.populateResourceTableSearchParamsPresentFlags(entity);
entity.setIndexStatus(INDEX_STATUS_INDEXED);
populateFullTextFields(myContext, theResource, entity);
}
@ -1206,6 +1206,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
// Synchronize search param indexes
AddRemoveCount searchParamAddRemoveCount = myDaoSearchParamSynchronizer.synchronizeSearchParamsToDatabase(newParams, entity, existingParams);
newParams.populateResourceTableParamCollections(entity);
// Interceptor broadcast: JPA_PERFTRACE_INFO
if (!searchParamAddRemoveCount.isEmpty()) {
if (JpaInterceptorBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {

View File

@ -887,6 +887,30 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
}
@Test
public void testCreateThenUpdateInSameTransaction() {
Patient initialPatient = new Patient();
IIdType id = myPatientDao.create(initialPatient).getId().toUnqualifiedVersionless();
runInTransaction(() -> {
Patient p = new Patient();
p.setId(id);
p.setActive(true);
p.addName().setFamily("FAMILY");
myPatientDao.update(p);
p = new Patient();
p.setId(id);
p.setActive(false);
p.addName().setFamily("FAMILY2");
myPatientDao.update(p);
});
assertEquals(1, myPatientDao.search(SearchParameterMap.newSynchronous("name", new StringParam("family2"))).size());
assertEquals(1, myPatientDao.search(SearchParameterMap.newSynchronous("active", new TokenParam("false"))).size());
}
@Test
public void testCreateSummaryFails() {
Patient p = new Patient();

View File

@ -105,26 +105,30 @@ public final class ResourceIndexedSearchParams {
return myLinks;
}
public void setParamsOn(ResourceTable theEntity) {
theEntity.setParamsString(myStringParams);
public void populateResourceTableSearchParamsPresentFlags(ResourceTable theEntity) {
theEntity.setParamsStringPopulated(myStringParams.isEmpty() == false);
theEntity.setParamsToken(myTokenParams);
theEntity.setParamsTokenPopulated(myTokenParams.isEmpty() == false);
theEntity.setParamsNumber(myNumberParams);
theEntity.setParamsNumberPopulated(myNumberParams.isEmpty() == false);
theEntity.setParamsQuantity(myQuantityParams);
theEntity.setParamsQuantityPopulated(myQuantityParams.isEmpty() == false);
theEntity.setParamsDate(myDateParams);
theEntity.setParamsDatePopulated(myDateParams.isEmpty() == false);
theEntity.setParamsUri(myUriParams);
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
theEntity.setParamsCoords(myCoordsParams);
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
theEntity.setParamsCompositeStringUniquePresent(myCompositeStringUniques.isEmpty() == false);
theEntity.setResourceLinks(myLinks);
theEntity.setHasLinks(myLinks.isEmpty() == false);
}
public void populateResourceTableParamCollections(ResourceTable theEntity) {
theEntity.setParamsString(myStringParams);
theEntity.setParamsToken(myTokenParams);
theEntity.setParamsNumber(myNumberParams);
theEntity.setParamsQuantity(myQuantityParams);
theEntity.setParamsDate(myDateParams);
theEntity.setParamsUri(myUriParams);
theEntity.setParamsCoords(myCoordsParams);
theEntity.setResourceLinks(myLinks);
}
void setUpdatedTime(Date theUpdateTime) {
setUpdatedTime(myStringParams, theUpdateTime);
setUpdatedTime(myNumberParams, theUpdateTime);