diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java index 4252c0d50f4..a89a240ea20 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java @@ -49,7 +49,7 @@ public static void bulkDeleteHistoricCaseInstances(Collection caseInstan if (cmmnEngineConfiguration.isEnableEntityLinks()) { cmmnEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() - .bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(ScopeTypes.CMMN, caseInstanceIds); + .bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(ScopeTypes.CMMN, caseInstanceIds); } HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager(); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java index 6872d549b97..ec0dca619c3 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java @@ -213,7 +213,7 @@ public void recordHistoricCaseInstanceDeleted(String caseInstanceId, String tena if (cmmnEngineConfiguration.isEnableEntityLinks()) { cmmnEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() - .deleteHistoricEntityLinksByScopeIdAndScopeType(historicCaseInstance.getId(), ScopeTypes.CMMN); + .deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(historicCaseInstance.getId(), ScopeTypes.CMMN); } HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager(); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java index e7ee597fe02..8e15ffca8db 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java @@ -224,6 +224,11 @@ public static void deleteHistoricTask(String taskId, CmmnEngineConfiguration cmm cmmnEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().deleteHistoricIdentityLinksByTaskId(taskId); + if (cmmnEngineConfiguration.isEnableEntityLinks()) { + cmmnEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(taskId, ScopeTypes.TASK); + } + historicTaskService.deleteHistoricTask(historicTaskInstance); } } @@ -283,6 +288,11 @@ protected static void bulkDeleteHistoricTaskInstances(Collection taskIds cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds); cmmnEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForTaskIds(taskIds); + if (cmmnEngineConfiguration.isEnableEntityLinks()) { + cmmnEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(ScopeTypes.TASK, taskIds); + } + historicTaskService.bulkDeleteHistoricTaskInstances(taskIds); historicTaskService.bulkDeleteHistoricTaskLogEntriesForTaskIds(taskIds); diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java index 53faa786b82..0913788042d 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java @@ -20,6 +20,8 @@ import java.util.List; import org.flowable.cmmn.api.runtime.CaseInstance; +import org.flowable.cmmn.api.runtime.PlanItemInstance; +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; import org.flowable.cmmn.engine.impl.util.CommandContextUtil; import org.flowable.cmmn.engine.test.CmmnDeployment; import org.flowable.cmmn.test.FlowableCmmnTestCase; @@ -328,6 +330,93 @@ public ByteArrayEntity execute(CommandContext commandContext) { } } + @Test + @CmmnDeployment(resources = "org/flowable/cmmn/test/one-human-task-model.cmmn") + public void deleteHistoricTaskInstanceRemovesReferenceScopeOrphans() { + HistoryLevel historyLevel = cmmnEngineConfiguration.getHistoryLevel(); + try { + cmmnEngineConfiguration.setHistoryLevel(HistoryLevel.FULL); + CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("oneTaskCase") + .start(); + + Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult(); + + waitForAsyncHistoryExecutorToProcessAllJobs(); + + // The case-task entity link points at the task as the REFERENCE_SCOPE_ID_. + assertThat(cmmnHistoryService.getHistoricEntityLinkParentsForTask(task.getId())).isNotEmpty(); + + cmmnTaskService.complete(task.getId()); + waitForAsyncHistoryExecutorToProcessAllJobs(); + + cmmnHistoryService.deleteHistoricTaskInstance(task.getId()); + + assertThat(cmmnHistoryService.getHistoricEntityLinkParentsForTask(task.getId())).isEmpty(); + assertThat(cmmnHistoryService.getHistoricEntityLinkChildrenForTask(task.getId())).isEmpty(); + + cmmnHistoryService.deleteHistoricCaseInstance(caseInstance.getId()); + } finally { + cmmnEngineConfiguration.setHistoryLevel(historyLevel); + } + } + + @Test + @CmmnDeployment(resources = { + "org/flowable/cmmn/test/runtime/CaseTaskTest.testBasicBlocking.cmmn", + "org/flowable/cmmn/test/runtime/oneTaskCase.cmmn" + }) + public void deleteHistoricCaseInstanceRemovesReferenceScopeOrphans() { + HistoryLevel historyLevel = cmmnEngineConfiguration.getHistoryLevel(); + try { + cmmnEngineConfiguration.setHistoryLevel(HistoryLevel.FULL); + CaseInstance parentCase = cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .start(); + + // Trigger Task One so the entry sentry on the case task fires and the sub-case starts. + PlanItemInstance taskOnePlanItem = cmmnRuntimeService.createPlanItemInstanceQuery() + .caseInstanceId(parentCase.getId()) + .planItemDefinitionId("task1") + .planItemInstanceState(PlanItemInstanceState.ACTIVE) + .singleResult(); + cmmnRuntimeService.triggerPlanItemInstance(taskOnePlanItem.getId()); + + CaseInstance subCase = cmmnRuntimeService.createCaseInstanceQuery() + .caseDefinitionKey("oneTaskCase") + .singleResult(); + assertThat(subCase).isNotNull(); + + PlanItemInstance subTaskPlanItem = cmmnRuntimeService.createPlanItemInstanceQuery() + .caseInstanceId(subCase.getId()) + .planItemInstanceState(PlanItemInstanceState.ACTIVE) + .singleResult(); + cmmnRuntimeService.triggerPlanItemInstance(subTaskPlanItem.getId()); + + waitForAsyncHistoryExecutorToProcessAllJobs(); + + // The sub-case is propagated as the REFERENCE_SCOPE_ID_ in the parent's child entity link. + assertThat(cmmnHistoryService.getHistoricEntityLinkParentsForCaseInstance(subCase.getId())).isNotEmpty(); + + cmmnHistoryService.deleteHistoricCaseInstance(subCase.getId()); + + assertThat(cmmnHistoryService.getHistoricEntityLinkParentsForCaseInstance(subCase.getId())).isEmpty(); + assertThat(cmmnHistoryService.getHistoricEntityLinkChildrenForCaseInstance(subCase.getId())).isEmpty(); + + // Trigger Task Two so the parent case completes, then drop it from history. + PlanItemInstance taskTwoPlanItem = cmmnRuntimeService.createPlanItemInstanceQuery() + .caseInstanceId(parentCase.getId()) + .planItemDefinitionId("task2") + .planItemInstanceState(PlanItemInstanceState.ACTIVE) + .singleResult(); + cmmnRuntimeService.triggerPlanItemInstance(taskTwoPlanItem.getId()); + waitForAsyncHistoryExecutorToProcessAllJobs(); + cmmnHistoryService.deleteHistoricCaseInstance(parentCase.getId()); + } finally { + cmmnEngineConfiguration.setHistoryLevel(historyLevel); + } + } + protected void validateEmptyHistoricDataForCaseInstance(String caseInstanceId) { assertThat(cmmnHistoryService.createHistoricVariableInstanceQuery().caseInstanceId(caseInstanceId).list()).hasSize(0); assertThat(cmmnHistoryService.getHistoricIdentityLinksForCaseInstance(caseInstanceId)).hasSize(0); diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java index 618320af659..a57b3795f16 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java @@ -144,7 +144,8 @@ public void recordProcessInstanceDeleted(String processInstanceId, String proces processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().deleteHistoricIdentityLinksByProcessInstanceId(processInstanceId); if (processEngineConfiguration.isEnableEntityLinks()) { - processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService().deleteHistoricEntityLinksByScopeIdAndScopeType(processInstanceId, ScopeTypes.BPMN); + processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(processInstanceId, ScopeTypes.BPMN); } getCommentEntityManager().deleteCommentsByProcessInstanceId(processInstanceId); @@ -183,7 +184,8 @@ public void recordBulkDeleteProcessInstances(Collection processInstanceI processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForProcessInstanceIds(processInstanceIds); if (processEngineConfiguration.isEnableEntityLinks()) { - processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService().bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(ScopeTypes.BPMN, processInstanceIds); + processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(ScopeTypes.BPMN, processInstanceIds); } getCommentEntityManager().bulkDeleteCommentsForProcessInstanceIds(processInstanceIds); diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java index bacd277aec3..d46095ff6ea 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java @@ -660,6 +660,11 @@ public static void deleteHistoricTask(String taskId) { } processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().deleteHistoricIdentityLinksByTaskId(taskId); + if (processEngineConfiguration.isEnableEntityLinks()) { + processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(taskId, ScopeTypes.TASK); + } + historicTaskService.deleteHistoricTask(historicTaskInstance); } } @@ -712,6 +717,11 @@ protected static void bulkDeleteHistoricTaskInstances(Collection taskIds processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds); processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForTaskIds(taskIds); + if (processEngineConfiguration.isEnableEntityLinks()) { + processEngineConfiguration.getEntityLinkServiceConfiguration().getHistoricEntityLinkService() + .bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(ScopeTypes.TASK, taskIds); + } + historicTaskService.bulkDeleteHistoricTaskInstances(taskIds); historicTaskService.bulkDeleteHistoricTaskLogEntriesForTaskIds(taskIds); } diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java index a4b7a74db17..5dd76ec9785 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java @@ -456,6 +456,104 @@ public List execute(CommandContext commandContext) { } } + @Test + @Deployment(resources = { "org/flowable/engine/test/history/callActivity.bpmn20.xml", + "org/flowable/engine/test/history/subProcess.bpmn20.xml" }) + public void deleteHistoricTaskInstanceRemovesReferenceScopeOrphans() { + HistoryLevel historyLevel = processEngineConfiguration.getHistoryLevel(); + try { + processEngineConfiguration.setHistoryLevel(HistoryLevel.FULL); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("callActivity"); + + Task mainTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + taskService.complete(mainTask.getId()); + + ProcessInstance subProcessInstance = runtimeService.createProcessInstanceQuery().superProcessInstanceId(processInstance.getId()).singleResult(); + Task subTask = taskService.createTaskQuery().processInstanceId(subProcessInstance.getId()).singleResult(); + String subTaskId = subTask.getId(); + + // Complete the sub-task so it has an endTime; deleteHistoricTaskInstance only works on completed tasks. + taskService.complete(subTaskId); + waitForHistoryJobExecutorToProcessAllJobs(10000, 400); + + // The sub-process task carries a parent link (root scope = parent process instance) before delete. + assertThat(historyService.getHistoricEntityLinkParentsForTask(subTaskId)).isNotEmpty(); + + historyService.deleteHistoricTaskInstance(subTaskId); + + // After deleting only the historic task, no row in ACT_HI_ENTITYLINK may still reference it. + assertThat(historyService.getHistoricEntityLinkParentsForTask(subTaskId)).isEmpty(); + assertThat(historyService.getHistoricEntityLinkChildrenForTask(subTaskId)).isEmpty(); + + historyService.deleteHistoricProcessInstance(processInstance.getId()); + } finally { + processEngineConfiguration.setHistoryLevel(historyLevel); + } + } + + @Test + @Deployment(resources = { "org/flowable/engine/test/history/callActivity.bpmn20.xml", + "org/flowable/engine/test/history/subProcess.bpmn20.xml" }) + public void deleteHistoricProcessInstanceRemovesReferenceScopeOrphans() { + HistoryLevel historyLevel = processEngineConfiguration.getHistoryLevel(); + try { + processEngineConfiguration.setHistoryLevel(HistoryLevel.FULL); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("callActivity"); + + Task mainTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + taskService.complete(mainTask.getId()); + + ProcessInstance subProcessInstance = runtimeService.createProcessInstanceQuery().superProcessInstanceId(processInstance.getId()).singleResult(); + Task subTask = taskService.createTaskQuery().processInstanceId(subProcessInstance.getId()).singleResult(); + taskService.complete(subTask.getId()); + + waitForHistoryJobExecutorToProcessAllJobs(10000, 400); + + // The sub-process is propagated as the REFERENCE_SCOPE_ID_ in the parent's child entity link. + assertThat(historyService.getHistoricEntityLinkParentsForProcessInstance(subProcessInstance.getId())).isNotEmpty(); + + historyService.deleteHistoricProcessInstance(subProcessInstance.getId()); + + assertThat(historyService.getHistoricEntityLinkParentsForProcessInstance(subProcessInstance.getId())).isEmpty(); + assertThat(historyService.getHistoricEntityLinkChildrenForProcessInstance(subProcessInstance.getId())).isEmpty(); + + historyService.deleteHistoricProcessInstance(processInstance.getId()); + } finally { + processEngineConfiguration.setHistoryLevel(historyLevel); + } + } + + @Test + @Deployment(resources = { "org/flowable/engine/test/history/callActivity.bpmn20.xml", + "org/flowable/engine/test/history/subProcess.bpmn20.xml" }) + public void bulkDeleteHistoricProcessInstancesRemovesReferenceScopeOrphans() { + HistoryLevel historyLevel = processEngineConfiguration.getHistoryLevel(); + try { + processEngineConfiguration.setHistoryLevel(HistoryLevel.FULL); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("callActivity"); + + Task mainTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); + taskService.complete(mainTask.getId()); + + ProcessInstance subProcessInstance = runtimeService.createProcessInstanceQuery().superProcessInstanceId(processInstance.getId()).singleResult(); + Task subTask = taskService.createTaskQuery().processInstanceId(subProcessInstance.getId()).singleResult(); + taskService.complete(subTask.getId()); + + waitForHistoryJobExecutorToProcessAllJobs(10000, 400); + + assertThat(historyService.getHistoricEntityLinkParentsForProcessInstance(subProcessInstance.getId())).isNotEmpty(); + + historyService.bulkDeleteHistoricProcessInstances(Collections.singletonList(subProcessInstance.getId())); + + assertThat(historyService.getHistoricEntityLinkParentsForProcessInstance(subProcessInstance.getId())).isEmpty(); + assertThat(historyService.getHistoricEntityLinkChildrenForProcessInstance(subProcessInstance.getId())).isEmpty(); + + historyService.deleteHistoricProcessInstance(processInstance.getId()); + } finally { + processEngineConfiguration.setHistoryLevel(historyLevel); + } + } + protected void validateEmptyHistoricDataForProcessInstance(String processInstanceId) { assertThat(historyService.createHistoricDetailQuery().processInstanceId(processInstanceId).list()).hasSize(0); assertThat(historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list()).hasSize(0); diff --git a/modules/flowable-entitylink-service-api/src/main/java/org/flowable/entitylink/api/history/HistoricEntityLinkService.java b/modules/flowable-entitylink-service-api/src/main/java/org/flowable/entitylink/api/history/HistoricEntityLinkService.java index 1f8fd1304da..2092ddfd3bc 100644 --- a/modules/flowable-entitylink-service-api/src/main/java/org/flowable/entitylink/api/history/HistoricEntityLinkService.java +++ b/modules/flowable-entitylink-service-api/src/main/java/org/flowable/entitylink/api/history/HistoricEntityLinkService.java @@ -66,9 +66,22 @@ default List findHistoricEntityLinksByScopeDefinitionIdAndSc void deleteHistoricEntityLinksByScopeIdAndScopeType(String scopeId, String scopeType); + /** + * Delete every historic entity link where the given id appears as either the scope id + * (with the given scope type) or the reference scope id (with the given reference scope type). + * Used when an entity is removed from history to ensure no orphan rows are left pointing at it + * from either direction. + */ + void deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(String id, String scopeType); + void deleteHistoricEntityLinksByScopeDefinitionIdAndScopeType(String scopeDefinitionId, String scopeType); void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(String scopeType, Collection scopeIds); + + /** + * Bulk variant of {@link #deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(String, String)}. + */ + void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids); void deleteHistoricEntityLinksForNonExistingProcessInstances(); diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/HistoricEntityLinkServiceImpl.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/HistoricEntityLinkServiceImpl.java index 6b0fcd9fb5f..e73acef16fa 100644 --- a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/HistoricEntityLinkServiceImpl.java +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/HistoricEntityLinkServiceImpl.java @@ -78,6 +78,11 @@ public void deleteHistoricEntityLinksByScopeIdAndScopeType(String scopeId, Strin getHistoricEntityLinkEntityManager().deleteHistoricEntityLinksByScopeIdAndScopeType(scopeId, scopeType); } + @Override + public void deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(String id, String scopeType) { + getHistoricEntityLinkEntityManager().deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(id, scopeType); + } + @Override public void deleteHistoricEntityLinksByScopeDefinitionIdAndScopeType(String scopeDefinitionId, String scopeType) { getHistoricEntityLinkEntityManager().deleteHistoricEntityLinksByScopeDefinitionIdAndScopeType(scopeDefinitionId, scopeType); @@ -88,6 +93,11 @@ public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(String scopeTyp getHistoricEntityLinkEntityManager().bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(scopeType, scopeIds); } + @Override + public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids) { + getHistoricEntityLinkEntityManager().bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(scopeType, ids); + } + @Override public void deleteHistoricEntityLinksForNonExistingProcessInstances() { getHistoricEntityLinkEntityManager().deleteHistoricEntityLinksForNonExistingProcessInstances(); diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManager.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManager.java index fe03cba1e9a..c603d46bf47 100644 --- a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManager.java +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManager.java @@ -32,10 +32,14 @@ public interface HistoricEntityLinkEntityManager extends EntityManager scopeIds); + void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids); + void deleteHistoricEntityLinksForNonExistingProcessInstances(); void deleteHistoricEntityLinksForNonExistingCaseInstances(); diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManagerImpl.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManagerImpl.java index 3f91e3f8791..d36154ecac9 100644 --- a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManagerImpl.java +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/HistoricEntityLinkEntityManagerImpl.java @@ -61,6 +61,11 @@ public void deleteHistoricEntityLinksByScopeIdAndScopeType(String scopeId, Strin dataManager.deleteHistoricEntityLinksByScopeIdAndType(scopeId, scopeType); } + @Override + public void deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType(String id, String scopeType) { + dataManager.deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndType(id, scopeType); + } + @Override public void deleteHistoricEntityLinksByScopeDefinitionIdAndScopeType(String scopeDefinitionId, String scopeType) { dataManager.deleteHistoricEntityLinksByScopeDefinitionIdAndType(scopeDefinitionId, scopeType); @@ -71,6 +76,11 @@ public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(String scopeTyp dataManager.bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(scopeType, scopeIds); } + @Override + public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids) { + dataManager.bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(scopeType, ids); + } + @Override public void deleteHistoricEntityLinksForNonExistingProcessInstances() { dataManager.deleteHistoricEntityLinksForNonExistingProcessInstances(); diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/HistoricEntityLinkDataManager.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/HistoricEntityLinkDataManager.java index fd93303b92d..2b24c5b9f25 100644 --- a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/HistoricEntityLinkDataManager.java +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/HistoricEntityLinkDataManager.java @@ -35,9 +35,13 @@ public interface HistoricEntityLinkDataManager extends DataManager scopeIds); + + void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids); void deleteHistoricEntityLinksForNonExistingProcessInstances(); diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/impl/MybatisHistoricEntityLinkDataManager.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/impl/MybatisHistoricEntityLinkDataManager.java index a3b076225f9..f775da71419 100644 --- a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/impl/MybatisHistoricEntityLinkDataManager.java +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/persistence/entity/data/impl/MybatisHistoricEntityLinkDataManager.java @@ -101,6 +101,14 @@ public void deleteHistoricEntityLinksByScopeIdAndType(String scopeId, String sco getDbSqlSession().delete("deleteHistoricEntityLinksByScopeIdAndScopeType", parameters, HistoricEntityLinkEntityImpl.class); } + @Override + public void deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndType(String id, String scopeType) { + Map parameters = new HashMap<>(); + parameters.put("id", id); + parameters.put("scopeType", scopeType); + getDbSqlSession().delete("deleteHistoricEntityLinksByScopeIdOrReferenceScopeIdAndScopeType", parameters, HistoricEntityLinkEntityImpl.class); + } + @Override public void deleteHistoricEntityLinksByScopeDefinitionIdAndType(String scopeDefinitionId, String scopeType) { Map parameters = new HashMap<>(); @@ -117,6 +125,14 @@ public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds(String scopeTyp getDbSqlSession().delete("bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIds", parameters, HistoricEntityLinkEntityImpl.class); } + @Override + public void bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds(String scopeType, Collection ids) { + Map parameters = new HashMap<>(); + parameters.put("scopeType", scopeType); + parameters.put("ids", createSafeInValuesList(ids)); + getDbSqlSession().delete("bulkDeleteHistoricEntityLinksForScopeTypeAndScopeIdsOrReferenceScopeIds", parameters, HistoricEntityLinkEntityImpl.class); + } + @Override public void deleteHistoricEntityLinksForNonExistingProcessInstances() { getDbSqlSession().delete("bulkDeleteHistoricProcessEntityLinks", null, HistoricEntityLinkEntityImpl.class); diff --git a/modules/flowable-entitylink-service/src/main/resources/org/flowable/entitylink/service/db/mapping/entity/HistoricEntityLink.xml b/modules/flowable-entitylink-service/src/main/resources/org/flowable/entitylink/service/db/mapping/entity/HistoricEntityLink.xml index c9ab63e6cb0..00230b513fb 100644 --- a/modules/flowable-entitylink-service/src/main/resources/org/flowable/entitylink/service/db/mapping/entity/HistoricEntityLink.xml +++ b/modules/flowable-entitylink-service/src/main/resources/org/flowable/entitylink/service/db/mapping/entity/HistoricEntityLink.xml @@ -87,6 +87,12 @@ delete from ${prefix}ACT_HI_ENTITYLINK where SCOPE_ID_ = #{scopeId, jdbcType=NVARCHAR} and SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR} + + delete from ${prefix}ACT_HI_ENTITYLINK + where (SCOPE_ID_ = #{id, jdbcType=NVARCHAR} and SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR}) + or (REF_SCOPE_ID_ = #{id, jdbcType=NVARCHAR} and REF_SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR}) + + delete from ${prefix}ACT_HI_ENTITYLINK where SCOPE_DEFINITION_ID_ = #{scopeDefinitionId, jdbcType=NVARCHAR} and SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR} @@ -103,6 +109,31 @@ ) + + + delete from ${prefix}ACT_HI_ENTITYLINK where + (SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR} and + ( + + or + + SCOPE_ID_ in + + #{id, jdbcType=NVARCHAR} + + )) + or + (REF_SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR} and + ( + + or + + REF_SCOPE_ID_ in + + #{id, jdbcType=NVARCHAR} + + )) + delete from ${prefix}ACT_HI_ENTITYLINK where SCOPE_TYPE_ = 'bpmn' and NOT EXISTS (select PROCINST.ID_ from ${prefix}ACT_HI_PROCINST PROCINST where SCOPE_ID_ = PROCINST.ID_)