diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
index 10a25de603ee055c7fe9006b832ed3c919d04680..9949b4a770392bcbc846f494e6906c994d8268b4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
@@ -546,7 +546,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
                         sample.getIdentifier(), parentToAdd.getIdentifier());
             } else
             {
-                final Set<TechId> nextToVisit = getSampleDAO().listParents(toVisit, relationship);
+                final Set<TechId> nextToVisit = getSampleDAO().listSampleIdsByChildrenIds(toVisit, relationship);
                 visited.addAll(toVisit);
                 nextToVisit.removeAll(visited);
                 toVisit = nextToVisit;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
index 170707cc51d3ea5f7c6a69e91f8c260dbcfa784c..4c73d12f65ee6c42c4b804447f2393eec07ea8db 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
@@ -235,15 +235,17 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
         dataSets.addAll(getDataDAO().listDataSets(experiment));
     }
 
-    public void trashLoadedDataSets(DeletionPE deletion)
+    public int trashByTechIds(List<TechId> dataSetIds, DeletionPE deletion)
+            throws UserFailureException
     {
         try
         {
-            getDataDAO().trash(dataSets, deletion);
+            return getDataDAO().trash(dataSetIds, deletion);
         } catch (final DataAccessException ex)
         {
             throwException(ex, "Data Set", EntityKind.DATA_SET);
         }
+        return -1; // not possible
     }
 
     public void deleteLoadedDataSets(String reason)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
index 3a4d955105c3596eace446586f098daec1bedd6e..20348f239ed3d73dd30ab3cd3bff3bbc1fbfcb18 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBO.java
@@ -39,6 +39,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.api.IManagedProperty;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE.EntityType;
@@ -47,7 +48,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
@@ -208,19 +208,17 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
                 + "') not found in experiment '" + experiment.getIdentifier() + "'.");
     }
 
-    public void trashByTechIds(List<TechId> experimentIds, DeletionPE deletion)
+    public int trashByTechIds(List<TechId> experimentIds, DeletionPE deletion)
             throws UserFailureException
     {
         try
         {
-            getSessionFactory().getCurrentSession().flush();
-            getSessionFactory().getCurrentSession().clear();
-
-            getExperimentDAO().trash(experimentIds, deletion);
+            return getExperimentDAO().trash(experimentIds, deletion);
         } catch (final DataAccessException ex)
         {
             throwException(ex, "Experiment", EntityKind.EXPERIMENT);
         }
+        return -1; // not possible
     }
 
     public void deleteByTechIds(List<TechId> experimentIds, String reason)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
index 270b74eb5b4454d862f8cd84f2a6dce453f5ebcc..d3bb6d8ffc3b250dc0510a97d772153eb2f84c7c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo;
 import java.util.List;
 import java.util.Map;
 
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkModel;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewDataSet;
@@ -70,9 +71,13 @@ public interface IDataSetTable
     void setDataSets(List<DataPE> dataSets);
 
     /**
-     * Moves loaded data sets to trash for specified reason.
+     * Moves data sets to trash with given deletion.
+     * 
+     * @param dataSetIds data set technical identifiers
+     * @throws UserFailureException if one of the data sets can not be moved to trash.
      */
-    void trashLoadedDataSets(DeletionPE deletion);
+    public int trashByTechIds(List<TechId> dataSetIds, DeletionPE deletion)
+            throws UserFailureException;
 
     /**
      * Permanently Deletes loaded data sets for specified reason.
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentBO.java
index 668340e2f37c6a41d1d6433e42b6efd2e035bdf1..6d4512b92111263d5aad09625e277872afa28b63 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentBO.java
@@ -89,7 +89,7 @@ public interface IExperimentBO extends IEntityBusinessObject
      * @param experimentIds experiment technical identifiers
      * @throws UserFailureException if one of the experiments can not be moved to trash.
      */
-    void trashByTechIds(List<TechId> experimentIds, DeletionPE deletion);
+    int trashByTechIds(List<TechId> experimentIds, DeletionPE deletion);
 
     /**
      * Changes the value of a managed property.
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleTable.java
index 68a1b38f937e42961ef7112126130bd8a0493e3e..1fa3e8fcc176a2e41fd8a798af9e8c37dc0eacea 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleTable.java
@@ -78,7 +78,7 @@ public interface ISampleTable
      * @param sampleIds sample technical identifiers
      * @throws UserFailureException if one of the samples can not be moved to trash.
      */
-    public void trashByTechIds(List<TechId> sampleIds, DeletionPE deletion)
+    public int trashByTechIds(List<TechId> sampleIds, DeletionPE deletion)
             throws UserFailureException;
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
index e155d2689ded13ac1660d7158bef12212b6f3679..300a60a559c61ebed9107362d109208016bb6b07 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
@@ -19,7 +19,6 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo;
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 
 /**
  * Handles the trash of entities.
@@ -34,7 +33,7 @@ public interface ITrashBO
 
     public void trashExperiments(List<TechId> experimentIds);
 
-    public void trashDataSets(List<DataPE> dataSets);
+    public void trashDataSets(List<TechId> dataSetIds);
 
     /** Puts back all entities moved to trash in deletion with specified id. */
     public void revertDeletion(TechId deletionId);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java
index 5c2f74eb54047a9a8a3ee3839d950c91b4ac53cb..5942b4b7f07601b0d445a63e0f49033243de4a01 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java
@@ -31,10 +31,10 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleBatchUpdateDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePropertyTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
@@ -341,19 +341,17 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I
         }
     }
 
-    public void trashByTechIds(List<TechId> sampleIds, DeletionPE deletion)
+    public int trashByTechIds(List<TechId> sampleIds, DeletionPE deletion)
             throws UserFailureException
     {
         try
         {
-            getSessionFactory().getCurrentSession().flush();
-            getSessionFactory().getCurrentSession().clear();
-
-            getSampleDAO().trash(sampleIds, deletion);
+            return getSampleDAO().trash(sampleIds, deletion);
         } catch (final DataAccessException ex)
         {
             throwException(ex, "Sample", EntityKind.SAMPLE);
         }
+        return -1; // not possible
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
index 8132222cf562894f429ceb86e3e8dccb9080f7b2..de43071759f206b50b0b0052c9f2359ef3d67efe 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
@@ -16,13 +16,15 @@
 
 package ch.systemsx.cisd.openbis.generic.server.business.bo;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.springframework.dao.DataAccessException;
 
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 
@@ -60,22 +62,57 @@ public class TrashBO extends AbstractBusinessObject implements ITrashBO
     {
         assert deletion != null;
         ISampleTable sampleTableBO = boFactory.createSampleTable(session);
-        sampleTableBO.trashByTechIds(sampleIds, deletion);
+        int trashedCount = sampleTableBO.trashByTechIds(sampleIds, deletion);
+        if (trashedCount > 0)
+        {
+            trashSampleDependentChildrenAndComponents(sampleIds);
+            trashSampleDependentDataSets(sampleIds);
+        }
     }
 
     public void trashExperiments(List<TechId> experimentIds)
     {
         assert deletion != null;
         IExperimentBO experimentBO = boFactory.createExperimentBO(session);
-        experimentBO.trashByTechIds(experimentIds, deletion);
+        int trashedCount = experimentBO.trashByTechIds(experimentIds, deletion);
+        if (trashedCount > 0)
+        {
+            trashExperimentDependentDataSets(experimentIds);
+            trashExperimentDependentSamples(experimentIds);
+        }
     }
 
-    public void trashDataSets(List<DataPE> dataSets)
+    public void trashDataSets(List<TechId> dataSetIds)
     {
         assert deletion != null;
         IDataSetTable dataSetTable = boFactory.createDataSetTable(session);
-        dataSetTable.setDataSets(dataSets);
-        dataSetTable.trashLoadedDataSets(deletion);
+        dataSetTable.trashByTechIds(dataSetIds, deletion);
+        // NOTE: data set children are not cascade trashed - a conscious decision made by Tomek
+    }
+
+    private void trashSampleDependentChildrenAndComponents(List<TechId> sampleIds)
+    {
+        ISampleDAO sampleDAO = getSampleDAO();
+        trashSamples(new ArrayList<TechId>(sampleDAO.listSampleIdsByParentIds(sampleIds)));
+        trashSamples(sampleDAO.listSampleIdsByContainerIds(sampleIds));
+    }
+
+    private void trashSampleDependentDataSets(List<TechId> sampleIds)
+    {
+        IDataDAO dataDAO = getDataDAO();
+        trashDataSets(dataDAO.listDataSetIdsBySampleIds(sampleIds));
+    }
+
+    private void trashExperimentDependentSamples(List<TechId> experimentIds)
+    {
+        ISampleDAO sampleDAO = getSampleDAO();
+        trashSamples(sampleDAO.listSampleIdsByExperimentIds(experimentIds));
+    }
+
+    private void trashExperimentDependentDataSets(List<TechId> experimentIds)
+    {
+        IDataDAO dataDAO = getDataDAO();
+        trashDataSets(dataDAO.listDataSetIdsByExperimentIds(experimentIds));
     }
 
     public void revertDeletion(TechId deletionId)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataDAO.java
index 67fb17eb21e8355559a9645c9701feb5810a2f64..d79f4e2a933a9ca0249a3b1a7c01281071add610 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataDAO.java
@@ -120,9 +120,13 @@ public interface IDataDAO extends IGenericDAO<DataPE>
 
     public void updateDataSets(List<DataPE> externalData);
 
-    /**
-     * Move given data sets to trash using specified deletion.
-     */
-    public void trash(List<DataPE> dataSets, DeletionPE deletion) throws DataAccessException;
+    /** Move given data sets to trash using specified deletion. */
+    public int trash(List<TechId> dataSetIds, DeletionPE deletion) throws DataAccessException;
+
+    /** Returns ids of data sets connected with samples specified by given ids. */
+    public List<TechId> listDataSetIdsBySampleIds(final Collection<TechId> samples);
+
+    /** Returns ids of data sets connected with experiments specified by given ids. */
+    public List<TechId> listDataSetIdsByExperimentIds(final Collection<TechId> samples);
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
index 8a52959b90e4255d20bf7fb37df99c1007f345b1..924057cf6fef822f38fdf30449993a4e34091136 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java
@@ -110,6 +110,6 @@ public interface IExperimentDAO extends IGenericDAO<ExperimentPE>
     /**
      * Move experiments with given ids to trash using specified deletion.
      */
-    public void trash(List<TechId> experimentIds, DeletionPE deletion);
+    public int trash(List<TechId> experimentIds, DeletionPE deletion);
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ISampleDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ISampleDAO.java
index b136bfeafa3c809a7084504f7fd22acc23c7ad7d..bb35bce72172e509518765e730103512adb72c43 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ISampleDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ISampleDAO.java
@@ -93,16 +93,25 @@ public interface ISampleDAO extends IGenericDAO<SamplePE>
     List<SamplePE> listSamplesByGeneratedFrom(final SamplePE sample) throws DataAccessException;
 
     /**
-     * @return Unique set of ids of parents of data sets specified by ids.
-     *         <p>
-     *         NOTE: does not check if specified ids are proper data set ids.
+     * Returns ids of parents of samples specified by given ids and connected by chosen relationship
+     * type.
      */
+    public Set<TechId> listSampleIdsByChildrenIds(Collection<TechId> children, TechId relationship);
 
     /**
-     * Returns ids of parents of samples specified by given ids and connected by chosen relationship
-     * type.
+     * Returns ids of children of samples specified by given ids.
+     * <p>
+     * NOTES:
+     * <li>we don't use relationship type as don't really support different relationship types
+     * <li>we need a set as the connection is many-to-many and we want unique ids
      */
-    public Set<TechId> listParents(Collection<TechId> children, TechId relationship);
+    public Set<TechId> listSampleIdsByParentIds(Collection<TechId> parentIds);
+
+    /** Returns ids of components of samples specified by given ids. */
+    public List<TechId> listSampleIdsByContainerIds(Collection<TechId> containerIds);
+
+    /** Returns ids of samples connected with experiments specified by given ids. */
+    List<TechId> listSampleIdsByExperimentIds(Collection<TechId> experimentIds);
 
     /**
      * Lists samples (with minimal additional information) belonging to the given <code>space</code>
@@ -126,5 +135,6 @@ public interface ISampleDAO extends IGenericDAO<SamplePE>
     /**
      * Move samples with given ids to trash using specified deletion.
      */
-    void trash(List<TechId> sampleIds, DeletionPE deletion) throws DataAccessException;
+    int trash(List<TechId> sampleIds, DeletionPE deletion) throws DataAccessException;
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataDAO.java
index 8eb96cea9308f049b95304d55d145a6d785cf630..650a1753641d783cfefadfb6e4123483daf25dcb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataDAO.java
@@ -464,18 +464,40 @@ final class DataDAO extends AbstractGenericEntityWithPropertiesDAO<DataPE> imple
         super.delete(entity);
     }
 
-    public void trash(List<DataPE> dataSets, DeletionPE deletion) throws DataAccessException
+    public int trash(final List<TechId> dataSetIds, final DeletionPE deletion)
+            throws DataAccessException
     {
-        // TODO 2011-06-16, Piotr Buczek: could be done faster with bulk update
-        for (DataPE dataSet : dataSets)
+        if (dataSetIds.isEmpty())
         {
-            if (dataSet.getDeletion() == null)
-            {
-                dataSet.setDeletion(deletion);
-            }
+            return 0;
         }
+        final HibernateTemplate hibernateTemplate = getHibernateTemplate();
+        int updatedRows = (Integer) hibernateTemplate.execute(new HibernateCallback()
+            {
+
+                //
+                // HibernateCallback
+                //
 
-        getHibernateTemplate().flush();
+                public final Object doInHibernate(final Session session) throws HibernateException,
+                        SQLException
+                {
+                    // NOTE: 'VERSIONED' makes modification time modified too
+                    return session
+                            .createQuery(
+                                    "UPDATE VERSIONED "
+                                            + DataPE.class.getSimpleName()
+                                            + " SET deletion = :deletion WHERE deletion IS NULL AND id IN (:ids) ")
+                            .setParameter("deletion", deletion)
+                            .setParameterList("ids", TechId.asLongs(dataSetIds)).executeUpdate();
+                }
+            });
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format("trashing %d data sets", updatedRows));
+        }
+        hibernateTemplate.flush();
+        return updatedRows;
     }
 
     @SuppressWarnings("unchecked")
@@ -556,4 +578,33 @@ final class DataDAO extends AbstractGenericEntityWithPropertiesDAO<DataPE> imple
         scheduleDynamicPropertiesEvaluation(Arrays.asList(entity));
     }
 
+    public List<TechId> listDataSetIdsBySampleIds(final Collection<TechId> samples)
+    {
+        final DetachedCriteria criteria = DetachedCriteria.forClass(DataPE.class);
+        final List<Long> longIds = TechId.asLongs(samples);
+        criteria.setProjection(Projections.id());
+        criteria.add(Restrictions.in("sampleInternal.id", longIds));
+        final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
+        if (operationLog.isDebugEnabled())
+        {
+           operationLog.info(String.format("found %s data sets for given samples", results.size()));
+        }
+        return transformNumbers2TechIdList(results);
+    }
+
+    public List<TechId> listDataSetIdsByExperimentIds(final Collection<TechId> experiments)
+    {
+        final DetachedCriteria criteria = DetachedCriteria.forClass(DataPE.class);
+        final List<Long> longIds = TechId.asLongs(experiments);
+        criteria.setProjection(Projections.id());
+        criteria.add(Restrictions.in("experimentInternal.id", longIds));
+        final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
+        if (operationLog.isDebugEnabled())
+        {
+           operationLog
+                .info(String.format("found %s data sets for given experiments", results.size()));
+        }
+        return transformNumbers2TechIdList(results);
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
index 98d6a1632c93460dc3b1db32d461d0a4f89e3592..756de7db2665d3725ad1962b9ddb996c30eb814a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -25,9 +26,12 @@ import java.util.Set;
 import org.apache.log4j.Logger;
 import org.hibernate.Criteria;
 import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
 import org.hibernate.criterion.DetachedCriteria;
 import org.hibernate.criterion.Restrictions;
 import org.springframework.dao.DataAccessException;
+import org.springframework.orm.hibernate3.HibernateCallback;
 import org.springframework.orm.hibernate3.HibernateTemplate;
 
 import ch.systemsx.cisd.common.logging.LogCategory;
@@ -38,10 +42,10 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.PersistencyResources;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeConverter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentTypePE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 
@@ -300,20 +304,40 @@ public class ExperimentDAO extends AbstractGenericEntityWithPropertiesDAO<Experi
         }
     }
 
-    public void trash(final List<TechId> experimentIds, final DeletionPE deletion)
+    public int trash(final List<TechId> experimentIds, final DeletionPE deletion)
             throws DataAccessException
     {
-        // TODO 2011-06-16, Piotr Buczek: could be done faster with bulk update
-        for (TechId experimentId : experimentIds)
+        if (experimentIds.isEmpty())
         {
-            ExperimentPE experiment = loadByTechId(experimentId);
-            if (experiment.getDeletion() == null)
-            {
-                experiment.setDeletion(deletion);
-            }
+            return 0;
         }
+        final HibernateTemplate hibernateTemplate = getHibernateTemplate();
+        int updatedRows = (Integer) hibernateTemplate.execute(new HibernateCallback()
+            {
 
-        getHibernateTemplate().flush();
+                //
+                // HibernateCallback
+                //
+
+                public final Object doInHibernate(final Session session) throws HibernateException,
+                        SQLException
+                {
+                    // NOTE: 'VERSIONED' makes modification time modified too
+                    return session
+                            .createQuery(
+                                    "UPDATE VERSIONED "
+                                            + ExperimentPE.class.getSimpleName()
+                                            + " SET deletion = :deletion WHERE deletion IS NULL AND id IN (:ids) ")
+                            .setParameter("deletion", deletion)
+                            .setParameterList("ids", TechId.asLongs(experimentIds)).executeUpdate();
+                }
+            });
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format("trashing %d experiments", updatedRows));
+        }
+        hibernateTemplate.flush();
+        return updatedRows;
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
index 2c6e7f8067616c9568e0d6a5ad9ceb290377d58f..5f1d9619aad0886bbb01b4c2de48bb0fbbd20a97 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -25,11 +26,13 @@ import java.util.Set;
 import org.apache.log4j.Logger;
 import org.hibernate.Criteria;
 import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
 import org.hibernate.SQLQuery;
 import org.hibernate.Session;
 import org.hibernate.StatelessSession;
 import org.hibernate.criterion.Criterion;
 import org.hibernate.criterion.DetachedCriteria;
+import org.hibernate.criterion.Projections;
 import org.hibernate.criterion.Restrictions;
 import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.support.JdbcAccessor;
@@ -464,27 +467,48 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
         scheduleRemoveFromFullTextIndex(ids);
     }
 
-    public void trash(final List<TechId> sampleIds, final DeletionPE deletion)
+    public int trash(final List<TechId> sampleIds, final DeletionPE deletion)
             throws DataAccessException
     {
-        // TODO 2011-06-16, Piotr Buczek: could be done faster with bulk update
-        for (TechId sampleId : sampleIds)
+        if (sampleIds.isEmpty())
         {
-            SamplePE sample = loadByTechId(sampleId);
-            if (sample.getDeletion() == null)
-            {
-                sample.setDeletion(deletion);
-            }
+            return 0;
         }
+        final HibernateTemplate hibernateTemplate = getHibernateTemplate();
+        int updatedRows = (Integer) hibernateTemplate.execute(new HibernateCallback()
+            {
 
-        getHibernateTemplate().flush();
+                //
+                // HibernateCallback
+                //
+
+                public final Object doInHibernate(final Session session) throws HibernateException,
+                        SQLException
+                {
+                    // NOTE: 'VERSIONED' makes modification time modified too
+                    return session
+                            .createQuery(
+                                    "UPDATE VERSIONED "
+                                            + SamplePE.class.getSimpleName()
+                                            + " SET deletion = :deletion WHERE deletion IS NULL AND id IN (:ids) ")
+                            .setParameter("deletion", deletion)
+                            .setParameterList("ids", TechId.asLongs(sampleIds)).executeUpdate();
+                }
+            });
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format("trashing %d samples", updatedRows));
+        }
+        hibernateTemplate.flush();
+        return updatedRows;
     }
 
-    @SuppressWarnings("unchecked")
-    public Set<TechId> listParents(final Collection<TechId> children, final TechId relationship)
+    public Set<TechId> listSampleIdsByChildrenIds(final Collection<TechId> children,
+            final TechId relationship)
     {
         final String query =
                 "select sample_id_parent from sample_relationships where sample_id_child in (:ids) and relationship_id = :r ";
+        @SuppressWarnings("unchecked")
         final List<? extends Number> results =
                 (List<? extends Number>) getHibernateTemplate().execute(new HibernateCallback()
                     {
@@ -499,10 +523,65 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
         Set<TechId> result = transformNumbers2TechIdSet(results);
         if (operationLog.isDebugEnabled())
         {
-            operationLog.debug(String.format("%d sample parents(s) have been found.",
+            operationLog.debug(String.format("found %d sample parents for given children",
                     results.size()));
         }
         return result;
     }
 
+    public Set<TechId> listSampleIdsByParentIds(final Collection<TechId> parents)
+    {
+        final String query =
+                "SELECT sample_id_child FROM " + TableNames.SAMPLE_RELATIONSHIPS_TABLE
+                        + " WHERE sample_id_parent IN (:ids)";
+        @SuppressWarnings("unchecked")
+        final List<? extends Number> results =
+                (List<? extends Number>) getHibernateTemplate().execute(new HibernateCallback()
+                    {
+
+                        public final Object doInHibernate(final Session session)
+                        {
+                            final List<Long> longIds = TechId.asLongs(parents);
+                            return session.createSQLQuery(query).setParameterList("ids", longIds)
+                                    .list();
+                        }
+                    });
+        Set<TechId> result = transformNumbers2TechIdSet(results);
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.info(String.format("found %d sample children for given parents",
+                results.size()));
+        }
+        return result;
+    }
+
+    public List<TechId> listSampleIdsByContainerIds(final Collection<TechId> containers)
+    {
+        final DetachedCriteria criteria = DetachedCriteria.forClass(SamplePE.class);
+        final List<Long> longIds = TechId.asLongs(containers);
+        criteria.setProjection(Projections.id());
+        criteria.add(Restrictions.in("container.id", longIds));
+        final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
+        if (operationLog.isDebugEnabled())
+        {
+            operationLog.info(String.format("found %s sample components for given containers",
+                results.size()));
+        }
+        return transformNumbers2TechIdList(results);
+    }
+
+    public List<TechId> listSampleIdsByExperimentIds(final Collection<TechId> experiments)
+    {
+        final DetachedCriteria criteria = DetachedCriteria.forClass(SamplePE.class);
+        final List<Long> longIds = TechId.asLongs(experiments);
+        criteria.setProjection(Projections.id());
+        criteria.add(Restrictions.in("experimentInternal.id", longIds));
+        final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
+        // if (operationLog.isDebugEnabled())
+        // {
+        operationLog.info(String.format("found %s samples for given experiments", results.size()));
+        // }
+        return transformNumbers2TechIdList(results);
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
index ece3c1d0f9c516be8a828bbf09bbaad47825805b..6e4b59f02495a52bd1a7a9e62795973c88f09c19 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
@@ -27,6 +27,7 @@ import ch.systemsx.cisd.openbis.generic.server.batch.DataSetBatchUpdate;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataSetTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ITrashBO;
 import ch.systemsx.cisd.openbis.generic.server.plugin.IDataSetTypeSlaveServerPlugin;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DeletionType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
@@ -61,7 +62,7 @@ public class GenericDataSetTypeSlaveServerPlugin implements IDataSetTypeSlaveSer
             case TRASH:
                 ITrashBO trashBO = businessObjectFactory.createTrashBO(session);
                 trashBO.createDeletion(reason);
-                trashBO.trashDataSets(dataSets);
+                trashBO.trashDataSets(TechId.createList(dataSets));
                 break;
         }
     }