Changes to schema to loosen dependencies between Forced ID table and the Resource and Resource History tables.
This commit is contained in:
parent
f38370fbf7
commit
5d5b3d7639
|
@ -78,8 +78,6 @@ public class ExpungeEverythingService {
|
||||||
ourLog.info("BEGINNING GLOBAL $expunge");
|
ourLog.info("BEGINNING GLOBAL $expunge");
|
||||||
myTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
myTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||||
myTxTemplate.execute(t -> {
|
myTxTemplate.execute(t -> {
|
||||||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null"));
|
|
||||||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null"));
|
|
||||||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,6 @@ import org.junit.Test;
|
||||||
import org.springframework.aop.framework.AopProxyUtils;
|
import org.springframework.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
|
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -163,7 +162,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFetchTotalAccurateForSlowLoading() throws InterruptedException {
|
public void testFetchTotalAccurateForSlowLoading() {
|
||||||
create200Patients();
|
create200Patients();
|
||||||
|
|
||||||
mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(25);
|
mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(25);
|
||||||
|
@ -836,8 +835,6 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
// Because of the forced ID's bidirectional link HFJ_RESOURCE <-> HFJ_FORCED_ID
|
|
||||||
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
assertEquals(1, myResourceTableDao.count());
|
assertEquals(1, myResourceTableDao.count());
|
||||||
assertEquals(1, myResourceHistoryTableDao.count());
|
assertEquals(1, myResourceHistoryTableDao.count());
|
||||||
|
|
|
@ -61,6 +61,11 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
|
|
||||||
protected void init420() { // 20191015 - present
|
protected void init420() { // 20191015 - present
|
||||||
Builder version = forVersion(VersionEnum.V4_2_0);
|
Builder version = forVersion(VersionEnum.V4_2_0);
|
||||||
|
|
||||||
|
// Eliminate circular dependency.
|
||||||
|
version.onTable("HFJ_RESOURCE").dropColumn("20200130.1", "FORCED_ID_PID");
|
||||||
|
version.onTable("HFJ_RES_VER").dropColumn("20200130.2", "FORCED_ID_PID");
|
||||||
|
version.onTable("HFJ_RES_VER").addForeignKey("20200130.3", "FK_RESOURCE_HISTORY_RESOURCE").toColumn("RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init410() { // 20190815 - 20191014
|
protected void init410() { // 20190815 - 20191014
|
||||||
|
|
|
@ -45,11 +45,6 @@ public abstract class BaseHasResource implements IBaseResourceEntity, IBasePersi
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private FhirVersionEnum myFhirVersion;
|
private FhirVersionEnum myFhirVersion;
|
||||||
|
|
||||||
@OneToOne(optional = true, fetch = FetchType.LAZY, cascade = {}, orphanRemoval = false)
|
|
||||||
@JoinColumn(name = "FORCED_ID_PID")
|
|
||||||
@OptimisticLock(excluded = true)
|
|
||||||
private ForcedId myForcedId;
|
|
||||||
|
|
||||||
@Column(name = "HAS_TAGS", nullable = false)
|
@Column(name = "HAS_TAGS", nullable = false)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private boolean myHasTags;
|
private boolean myHasTags;
|
||||||
|
@ -96,29 +91,13 @@ public abstract class BaseHasResource implements IBaseResourceEntity, IBasePersi
|
||||||
myFhirVersion = theFhirVersion;
|
myFhirVersion = theFhirVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ForcedId getForcedId() {
|
abstract public ForcedId getForcedId();
|
||||||
return myForcedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setForcedId(ForcedId theForcedId) {
|
abstract public void setForcedId(ForcedId theForcedId);
|
||||||
myForcedId = theForcedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract Long getId();
|
public abstract Long getId();
|
||||||
|
|
||||||
@Override
|
|
||||||
public IdDt getIdDt() {
|
|
||||||
if (getForcedId() == null) {
|
|
||||||
Long id = getResourceId();
|
|
||||||
return new IdDt(getResourceType() + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
|
||||||
} else {
|
|
||||||
// Avoid a join query if possible
|
|
||||||
String forcedId = getTransientForcedId() != null ? getTransientForcedId() : getForcedId().getForcedId();
|
|
||||||
return new IdDt(getResourceType() + '/' + forcedId + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
return myDeleted != null;
|
return myDeleted != null;
|
||||||
|
|
|
@ -21,6 +21,8 @@ package ca.uhn.fhir.jpa.model.entity;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import org.hibernate.annotations.OptimisticLock;
|
import org.hibernate.annotations.OptimisticLock;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
@ -54,7 +56,11 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
|
||||||
@Column(name = "PID")
|
@Column(name = "PID")
|
||||||
private Long myId;
|
private Long myId;
|
||||||
|
|
||||||
@Column(name = "RES_ID")
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_RESOURCE_HISTORY_RESOURCE"))
|
||||||
|
private ResourceTable myResourceTable;
|
||||||
|
|
||||||
|
@Column(name = "RES_ID", nullable = false, updatable = false, insertable = false)
|
||||||
private Long myResourceId;
|
private Long myResourceId;
|
||||||
|
|
||||||
@Column(name = "RES_TYPE", length = ResourceTable.RESTYPE_LEN, nullable = false)
|
@Column(name = "RES_TYPE", length = ResourceTable.RESTYPE_LEN, nullable = false)
|
||||||
|
@ -165,4 +171,35 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
|
||||||
public ResourcePersistentId getPersistentId() {
|
public ResourcePersistentId getPersistentId() {
|
||||||
return new ResourcePersistentId(myResourceId);
|
return new ResourcePersistentId(myResourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceTable getResourceTable() {
|
||||||
|
return myResourceTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceTable(ResourceTable theResourceTable) {
|
||||||
|
myResourceTable = theResourceTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdDt getIdDt() {
|
||||||
|
if (getResourceTable().getForcedId() == null) {
|
||||||
|
Long id = getResourceId();
|
||||||
|
return new IdDt(getResourceType() + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
|
} else {
|
||||||
|
// Avoid a join query if possible
|
||||||
|
String forcedId = getTransientForcedId() != null ? getTransientForcedId() : getResourceTable().getForcedId().getForcedId();
|
||||||
|
return new IdDt(getResourceType() + '/' + forcedId + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForcedId getForcedId() {
|
||||||
|
return getResourceTable().getForcedId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setForcedId(ForcedId theForcedId) {
|
||||||
|
getResourceTable().setForcedId(theForcedId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.model.entity;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.jpa.model.search.IndexNonDeletedInterceptor;
|
import ca.uhn.fhir.jpa.model.search.IndexNonDeletedInterceptor;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
@ -199,26 +201,36 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
@OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
@OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private Collection<ResourceLink> myResourceLinksAsTarget;
|
private Collection<ResourceLink> myResourceLinksAsTarget;
|
||||||
|
|
||||||
@Column(name = "RES_TYPE", length = RESTYPE_LEN, nullable = false)
|
@Column(name = "RES_TYPE", length = RESTYPE_LEN, nullable = false)
|
||||||
@Field
|
@Field
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private String myResourceType;
|
private String myResourceType;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private Collection<SearchParamPresent> mySearchParamPresents;
|
private Collection<SearchParamPresent> mySearchParamPresents;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private Set<ResourceTag> myTags;
|
private Set<ResourceTag> myTags;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private transient boolean myUnchangedInCurrentOperation;
|
private transient boolean myUnchangedInCurrentOperation;
|
||||||
|
|
||||||
@Version
|
@Version
|
||||||
@Column(name = "RES_VER")
|
@Column(name = "RES_VER")
|
||||||
private long myVersion;
|
private long myVersion;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "myResourceTable", fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "myResourceTable", fetch = FetchType.LAZY)
|
||||||
private Collection<ResourceHistoryProvenanceEntity> myProvenance;
|
private Collection<ResourceHistoryProvenanceEntity> myProvenance;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private transient ResourceHistoryTable myCurrentVersionEntity;
|
private transient ResourceHistoryTable myCurrentVersionEntity;
|
||||||
|
|
||||||
|
@OneToOne(optional = true, fetch = FetchType.EAGER, cascade = {}, orphanRemoval = false, mappedBy = "myResource")
|
||||||
|
private ForcedId myForcedId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTag addTag(TagDefinition theTag) {
|
public ResourceTag addTag(TagDefinition theTag) {
|
||||||
for (ResourceTag next : getTags()) {
|
for (ResourceTag next : getTags()) {
|
||||||
|
@ -549,7 +561,7 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
retVal.setUpdated(getUpdated());
|
retVal.setUpdated(getUpdated());
|
||||||
retVal.setFhirVersion(getFhirVersion());
|
retVal.setFhirVersion(getFhirVersion());
|
||||||
retVal.setDeleted(getDeleted());
|
retVal.setDeleted(getDeleted());
|
||||||
retVal.setForcedId(getForcedId());
|
retVal.setResourceTable(this);
|
||||||
|
|
||||||
retVal.getTags().clear();
|
retVal.getTags().clear();
|
||||||
|
|
||||||
|
@ -606,4 +618,28 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
public ResourcePersistentId getPersistentId() {
|
public ResourcePersistentId getPersistentId() {
|
||||||
return new ResourcePersistentId(getId());
|
return new ResourcePersistentId(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForcedId getForcedId() {
|
||||||
|
return myForcedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setForcedId(ForcedId theForcedId) {
|
||||||
|
myForcedId = theForcedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdDt getIdDt() {
|
||||||
|
if (getForcedId() == null) {
|
||||||
|
Long id = getResourceId();
|
||||||
|
return new IdDt(getResourceType() + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
|
} else {
|
||||||
|
// Avoid a join query if possible
|
||||||
|
String forcedId = getTransientForcedId() != null ? getTransientForcedId() : getForcedId().getForcedId();
|
||||||
|
return new IdDt(getResourceType() + '/' + forcedId + '/' + Constants.PARAM_HISTORY + '/' + getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue