From 4cf2b86a3f186ecf85984e82a5e6625656b9f474 Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Fri, 5 Aug 2011 12:44:20 +0000
Subject: [PATCH] [LMS-2442] fixed logical deletion of samples by ordering
 deletions (first delete components, than containers)

SVN: 22350
---
 .../openbis/generic/server/CommonServer.java  | 15 +++++++----
 .../server/dataaccess/db/DeletionDAO.java     | 27 ++++++++++++++++---
 .../generic/shared/dto/DeletedSamplePE.java   | 14 ++++++++++
 3 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 49240394e26..db00e67a357 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -2410,9 +2410,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         checkSession(sessionToken);
 
         IDeletionDAO deletionDAO = getDAOFactory().getDeletionDAO();
-        // NOTE:
-        // - we can't do bulk deletions to preserve original reason
-        // - we keep findTrashed... methods with collections as arguments for future use
+        // NOTE: we can't do bulk deletions to preserve original reasons
         for (TechId deletionId : deletionIds)
         {
             DeletionPE deletion = deletionDAO.getByTechId(deletionId);
@@ -2423,8 +2421,15 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             List<String> trashedDataSets = deletionDAO.findTrashedDataSetCodes(singletonList);
             deleteDataSets(sessionToken, trashedDataSets, deletionReason, deletionType);
 
-            List<TechId> trashedSamples = deletionDAO.findTrashedSampleIds(singletonList);
-            deleteSamples(sessionToken, trashedSamples, deletionReason, deletionType);
+            // we need to first delete components and then containers not to break constraints
+            List<TechId> trashedComponentSamples =
+                    deletionDAO.findTrashedComponentSampleIds(singletonList);
+            deleteSamples(sessionToken, trashedComponentSamples, deletionReason, deletionType);
+            List<TechId> trashedNonComponentSamples =
+                    deletionDAO.findTrashedNonComponentSampleIds(singletonList);
+            deleteSamples(sessionToken, trashedNonComponentSamples, deletionReason, deletionType);
+            // List<TechId> trashedSamples = deletionDAO.findTrashedSampleIds(singletonList);
+            // deleteSamples(sessionToken, trashedSamples, deletionReason, deletionType);
 
             List<TechId> trashedExperiments = deletionDAO.findTrashedExperimentIds(singletonList);
             deleteExperiments(sessionToken, trashedExperiments, deletionReason, deletionType);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
index bced950f11b..e0c2e5085f1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
@@ -24,6 +24,7 @@ import org.apache.log4j.Logger;
 import org.hibernate.HibernateException;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
+import org.hibernate.criterion.Criterion;
 import org.hibernate.criterion.DetachedCriteria;
 import org.hibernate.criterion.Projections;
 import org.hibernate.criterion.Restrictions;
@@ -52,6 +53,10 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements IDeletionDAO
 {
 
+    private static final String DELETION_ID = "deletion.id";
+
+    private static final String CONTAINER_ID = "containerId";
+
     /**
      * This logger does not output any SQL statement. If you want to do so, you had better set an
      * appropriate debugging level for class {@link JdbcAccessor}. </p>
@@ -127,6 +132,18 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
         return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE);
     }
 
+    public List<TechId> findTrashedNonComponentSampleIds(final List<TechId> deletionIds)
+    {
+        return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE,
+                Restrictions.isNull(CONTAINER_ID));
+    }
+
+    public List<TechId> findTrashedComponentSampleIds(final List<TechId> deletionIds)
+    {
+        return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE,
+                Restrictions.isNotNull(CONTAINER_ID));
+    }
+
     public List<TechId> findTrashedExperimentIds(final List<TechId> deletionIds)
     {
         return findTrashedEntityIds(deletionIds, EntityKind.EXPERIMENT);
@@ -138,7 +155,7 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
                 DetachedCriteria.forClass(EntityKind.DATA_SET.getDeletedEntityClass());
         final List<Long> longIds = TechId.asLongs(deletionIds);
         criteria.setProjection(Projections.property("code"));
-        criteria.add(Restrictions.in("deletion.id", longIds));
+        criteria.add(Restrictions.in(DELETION_ID, longIds));
         final List<String> results = cast(getHibernateTemplate().findByCriteria(criteria));
         operationLog.info(String.format("found %s trashed %s(s)", results.size(),
                 EntityKind.DATA_SET.name()));
@@ -146,13 +163,17 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
     }
 
     private List<TechId> findTrashedEntityIds(final List<TechId> deletionIds,
-            final EntityKind entityKind)
+            final EntityKind entityKind, Criterion... additionalCriteria)
     {
         final DetachedCriteria criteria =
                 DetachedCriteria.forClass(entityKind.getDeletedEntityClass());
         final List<Long> longIds = TechId.asLongs(deletionIds);
         criteria.setProjection(Projections.id());
-        criteria.add(Restrictions.in("deletion.id", longIds));
+        criteria.add(Restrictions.in(DELETION_ID, longIds));
+        for (Criterion criterion : additionalCriteria)
+        {
+            criteria.add(criterion);
+        }
         final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
         operationLog
                 .info(String.format("found %s trashed %s(s)", results.size(), entityKind.name()));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
index 694cdedc7bf..18f2ebf0332 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.dto;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
@@ -46,6 +47,8 @@ public class DeletedSamplePE extends AbstractDeletedEntityPE
 
     private transient Long id;
 
+    private Long containerId;
+
     @Id
     @SequenceGenerator(name = SequenceNames.SAMPLE_SEQUENCE, sequenceName = SequenceNames.SAMPLE_SEQUENCE, allocationSize = 1)
     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SequenceNames.SAMPLE_SEQUENCE)
@@ -60,6 +63,17 @@ public class DeletedSamplePE extends AbstractDeletedEntityPE
         this.id = id;
     }
 
+    @Column(name = ColumnNames.PART_OF_SAMPLE_COLUMN, nullable = false, insertable = false, updatable = false)
+    public Long getContainerId()
+    {
+        return containerId;
+    }
+
+    public void setContainerId(final Long containerId)
+    {
+        this.containerId = containerId;
+    }
+
     //
     // Object
     //
-- 
GitLab