Don't update modified time when performing NOOP update in JPA

This commit is contained in:
James Agnew 2019-04-05 14:36:18 -04:00
parent bfd6066e99
commit 706af5d579
5 changed files with 82 additions and 10 deletions

View File

@ -1319,17 +1319,18 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, this, theUpdateTime, theEntity, theResource, existingParams); mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, this, theUpdateTime, theEntity, theResource, existingParams);
changed = populateResourceIntoEntity(theRequest, theResource, theEntity, true); changed = populateResourceIntoEntity(theRequest, theResource, theEntity, true);
if (changed.isChanged()) {
theEntity.setUpdated(theUpdateTime);
if (theResource instanceof IResource) {
theEntity.setLanguage(((IResource) theResource).getLanguage().getValue());
} else {
theEntity.setLanguage(((IAnyResource) theResource).getLanguageElement().getValue());
}
theEntity.setUpdated(theUpdateTime); newParams.setParamsOn(theEntity);
if (theResource instanceof IResource) { theEntity.setIndexStatus(INDEX_STATUS_INDEXED);
theEntity.setLanguage(((IResource) theResource).getLanguage().getValue()); populateFullTextFields(myContext, theResource, theEntity);
} else {
theEntity.setLanguage(((IAnyResource) theResource).getLanguageElement().getValue());
} }
newParams.setParamsOn(theEntity);
theEntity.setIndexStatus(INDEX_STATUS_INDEXED);
populateFullTextFields(myContext, theResource, theEntity);
} else { } else {
changed = populateResourceIntoEntity(theRequest, theResource, theEntity, false); changed = populateResourceIntoEntity(theRequest, theResource, theEntity, false);

View File

@ -144,6 +144,17 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
return getQueriesForCurrentThreadStartingWith("delete"); return getQueriesForCurrentThreadStartingWith("delete");
} }
/**
* Log all captured UPDATE queries
*/
public void logUpdateQueriesForCurrentThread() {
List<String> queries = getUpdateQueriesForCurrentThread()
.stream()
.map(CircularQueueCaptureQueriesListener::formatQueryAsSql)
.collect(Collectors.toList());
ourLog.info("Select Queries:\n{}", String.join("\n", queries));
}
/** /**
* Log all captured SELECT queries * Log all captured SELECT queries
*/ */

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder; import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder; import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -102,7 +103,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
DataSource dataSource = ProxyDataSourceBuilder DataSource dataSource = ProxyDataSourceBuilder
.create(retVal) .create(retVal)
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL") .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
// .logSlowQueryBySlf4j(10, TimeUnit.SECONDS) // .logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
// .countQuery(new ThreadQueryCountHolder()) // .countQuery(new ThreadQueryCountHolder())
.beforeQuery(new BlockLargeNumbersOfParamsListener()) .beforeQuery(new BlockLargeNumbersOfParamsListener())

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.jpa.dao.r4; package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.TestUtil; import ca.uhn.fhir.jpa.util.TestUtil;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
@ -85,6 +87,58 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
} }
@Test
public void testUpdateNotModifiedDoesNotAffectDates() {
IIdType id = runInTransaction(() -> {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("2");
return myPatientDao.create(p).getId().toUnqualified();
});
String createTime = runInTransaction(()->{
List<ResourceTable> allResources = myResourceTableDao.findAll();
assertEquals(1, allResources.size());
ResourceTable resourceTable = allResources.get(0);
List<ResourceHistoryTable> allHistory = myResourceHistoryTableDao.findAll();
assertEquals(1, allHistory.size());
ResourceHistoryTable historyTable = allHistory.get(0);
assertEquals(resourceTable.getUpdated().getValueAsString(), historyTable.getUpdated().getValueAsString());
return resourceTable.getUpdated().getValueAsString();
});
myCaptureQueriesListener.clear();
runInTransaction(()->{
Patient p = new Patient();
p.setId(id.getIdPart());
p.addIdentifier().setSystem("urn:system").setValue("2");
myPatientDao.update(p);
});
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
// TODO: it'd be nice if this was lower
assertEquals(6, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
assertThat(myCaptureQueriesListener.getInsertQueriesForCurrentThread(), empty());
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
runInTransaction(()->{
List<ResourceTable> allResources = myResourceTableDao.findAll();
assertEquals(1, allResources.size());
ResourceTable resourceTable = allResources.get(0);
List<ResourceHistoryTable> allHistory = myResourceHistoryTableDao.findAll();
assertEquals(1, allHistory.size());
ResourceHistoryTable historyTable = allHistory.get(0);
assertEquals(createTime, historyTable.getUpdated().getValueAsString());
assertEquals(createTime, resourceTable.getUpdated().getValueAsString());
});
}
@Test @Test
public void testDuplicateProfilesIgnored() { public void testDuplicateProfilesIgnored() {
String name = "testDuplicateProfilesIgnored"; String name = "testDuplicateProfilesIgnored";

View File

@ -132,6 +132,11 @@
The second bug is that one case wasn't properly handled: when a resourceId with no version is provided. The second bug is that one case wasn't properly handled: when a resourceId with no version is provided.
This executed the case where only resource type is provided. This executed the case where only resource type is provided.
</action> </action>
<action type="fix">
When updating a resource in the JPA server, if the contents have not actually changed
the resource version is not updated and no new version is created. In this situation,
the update time was modified however. It will no longer be updated.
</action>
</release> </release>
<release version="3.7.0" date="2019-02-06" description="Gale"> <release version="3.7.0" date="2019-02-06" description="Gale">
<action type="add"> <action type="add">