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 ebdd4a86cf6e2c39de9dca641bb0e04013815979..0fa57e1cb497d584126a93a1927032e53c872e6c 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
@@ -580,38 +580,132 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
             Map<SampleOwnerIdentifier, SampleOwner> sampleOwnerCache)
     {
         assert sampleIdentifiers != null : "Sample identifiers unspecified.";
-        Map<SampleOwner, List<String>> samplesByOwner = new HashMap<SampleOwner, List<String>>();
+
+        Map<SampleOwnerWithContainer, List<String>> samplesByOwner =
+                new HashMap<SampleOwnerWithContainer, List<String>>();
         for (SampleIdentifier sampleIdentifier : sampleIdentifiers)
         {
             final SampleOwner sampleOwner = getSampleOwner(sampleOwnerCache, sampleIdentifier);
-            List<String> ownerSamples = samplesByOwner.get(sampleOwner);
+            final String containerCodeOrNull = sampleIdentifier.getContainerCodeOrNull();
+            final SampleOwnerWithContainer owner =
+                    new SampleOwnerWithContainer(sampleOwner, containerCodeOrNull);
+
+            List<String> ownerSamples = samplesByOwner.get(owner);
             if (ownerSamples == null)
             {
                 ownerSamples = new ArrayList<String>();
-                samplesByOwner.put(sampleOwner, ownerSamples);
+                samplesByOwner.put(owner, ownerSamples);
             }
-            ownerSamples.add(sampleIdentifier.getSampleCode());
+            ownerSamples.add(sampleIdentifier.getSampleSubCode());
         }
 
         final ISampleDAO sampleDAO = getSampleDAO();
         final List<SamplePE> results = new ArrayList<SamplePE>();
-        for (Entry<SampleOwner, List<String>> entry : samplesByOwner.entrySet())
+        for (Entry<SampleOwnerWithContainer, List<String>> entry : samplesByOwner.entrySet())
         {
-            SampleOwner sampleOwner = entry.getKey();
-            List<String> sampleCodes = entry.getValue();
+            final SampleOwnerWithContainer owner = entry.getKey();
+            final List<String> sampleCodes = entry.getValue();
+
+            final SampleOwner sampleOwner = owner.getSampleOwner();
+            final String containerCodeOrNull = owner.getContainerCodeOrNull();
+
             List<SamplePE> samples = null;
             if (sampleOwner.isDatabaseInstanceLevel())
             {
                 samples =
-                        sampleDAO.listByCodesAndDatabaseInstance(sampleCodes,
+                        sampleDAO.listByCodesAndDatabaseInstance(sampleCodes, containerCodeOrNull,
                                 sampleOwner.tryGetDatabaseInstance());
             } else
             {
                 assert sampleOwner.isGroupLevel() : "Must be of space level.";
-                samples = sampleDAO.listByCodesAndGroup(sampleCodes, sampleOwner.tryGetGroup());
+                samples =
+                        sampleDAO.listByCodesAndGroup(sampleCodes, containerCodeOrNull,
+                                sampleOwner.tryGetGroup());
             }
             results.addAll(samples);
         }
         return results;
     }
+
+    /** Helper class encapsulating {@link SampleOwner} and code of container of a sample. */
+    private static class SampleOwnerWithContainer
+    {
+        private final SampleOwner sampleOwner;
+
+        private final String containerCodeOrNull;
+
+        public SampleOwnerWithContainer(SampleOwner sampleOwner, String containerCodeOrNull)
+        {
+            assert sampleOwner != null;
+            this.sampleOwner = sampleOwner;
+            this.containerCodeOrNull = containerCodeOrNull;
+        }
+
+        public SampleOwner getSampleOwner()
+        {
+            return sampleOwner;
+        }
+
+        public String getContainerCodeOrNull()
+        {
+            return containerCodeOrNull;
+        }
+
+        //
+        // Object
+        //
+
+        @Override
+        public int hashCode()
+        {
+            final int prime = 31;
+            int result = 1;
+            result =
+                    prime * result
+                            + ((containerCodeOrNull == null) ? 0 : containerCodeOrNull.hashCode());
+            result = prime * result + sampleOwner.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            if (obj == null)
+            {
+                return false;
+            }
+            if (!(obj instanceof SampleOwnerWithContainer))
+            {
+                return false;
+            }
+            SampleOwnerWithContainer other = (SampleOwnerWithContainer) obj;
+            if (containerCodeOrNull == null)
+            {
+                if (other.containerCodeOrNull != null)
+                {
+                    return false;
+                }
+            } else if (!containerCodeOrNull.equals(other.containerCodeOrNull))
+            {
+                return false;
+            }
+            if (!sampleOwner.equals(other.sampleOwner))
+            {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString()
+        {
+            return "SampleOwnerWithContainer [sampleOwner=" + sampleOwner
+                    + ", containerCodeOrNull=" + containerCodeOrNull + "]";
+        }
+
+    }
 }
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 15eeecb5c8206fe3088948a675fe29ebf2cdb7e6..7b3b58b875ba85f46cf8187eaf8e5abc42df2c48 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
@@ -239,6 +239,7 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I
         batchUpdateProperties(sample, updates.getProperties(), details.getPropertiesToUpdate());
         checkPropertiesBusinessRules(sample, propertiesCache);
 
+        // TODO 2010-10-09, Piotr Buczek: don't check business rules if value wasn't changed
         if (details.isExperimentUpdateRequested())
         {
             updateGroup(sample, updates.getSampleIdentifier(), sampleOwnerCache);
@@ -325,27 +326,13 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I
             Map<SampleOwnerIdentifier, SampleOwner> sampleOwnerCache)
     {
         final List<SamplePE> results = new ArrayList<SamplePE>();
-        List<SampleIdentifier> identifiersToLoadInBatch = new ArrayList<SampleIdentifier>();
+        List<SampleIdentifier> identifiers = new ArrayList<SampleIdentifier>();
         for (SampleBatchUpdatesDTO sampleUpdates : updates)
         {
             SampleIdentifier identifier = sampleUpdates.getOldSampleIdentifierOrNull();
-            if (identifier.getSampleCode().contains(
-                    SampleIdentifier.CONTAINED_SAMPLE_CODE_SEPARARTOR_STRING))
-            {
-                // contained samples can't be loaded in batch
-                SamplePE sample = tryToGetSampleByIdentifier(identifier);
-                if (sample == null)
-                {
-                    throw UserFailureException.fromTemplate(
-                            "No sample could be found with given identifier '%s'.", identifier);
-                }
-                results.add(sample);
-            } else
-            {
-                identifiersToLoadInBatch.add(identifier);
-            }
+            identifiers.add(identifier);
         }
-        results.addAll(listSamplesByIdentifiers(identifiersToLoadInBatch, sampleOwnerCache));
+        results.addAll(listSamplesByIdentifiers(identifiers, sampleOwnerCache));
         return results;
     }
 
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 004d07d072f09b54eff78e2d5d2671eeaf31c8b8..a43dd770fbde8975eda5f01ec03874bbcb7531e5 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
@@ -54,9 +54,12 @@ public interface ISampleDAO extends IGenericDAO<SamplePE>
 
     /**
      * Returns a list of samples with given <var>databaseInstance</var> and one of given codes.
+     * 
+     * @param containerCodeOrNull if specified all returned samples should have container with
+     *            specified code, otherwise they shouldn't have any container
      */
     List<SamplePE> listByCodesAndDatabaseInstance(final List<String> sampleCodes,
-            final DatabaseInstancePE databaseInstance);
+            String containerCodeOrNull, final DatabaseInstancePE databaseInstance);
 
     /**
      * Returns the sample specified by given <var>sampleCode</var> and given <var>group</var>.
@@ -66,8 +69,12 @@ public interface ISampleDAO extends IGenericDAO<SamplePE>
 
     /**
      * Returns a list of samples with given <var>group</var> and one of given codes.
+     * 
+     * @param containerCodeOrNull if specified all returned samples should have container with
+     *            specified code, otherwise they shouldn't have any container
      */
-    List<SamplePE> listByCodesAndGroup(final List<String> sampleCodes, final GroupPE group);
+    List<SamplePE> listByCodesAndGroup(final List<String> sampleCodes, String containerCodeOrNull,
+            final GroupPE group);
 
     /**
      * Inserts given list of {@link SamplePE} into the database in one go.
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 e1e8090b4521d3cf119b8d5b152c5fe85f43a3eb..29f43837fb8767712f9063a7eeb8e8b9b4573569 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
@@ -207,13 +207,13 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
     }
 
     public final List<SamplePE> listByCodesAndDatabaseInstance(final List<String> sampleCodes,
-            final DatabaseInstancePE databaseInstance)
+            final String containerCodeOrNull, final DatabaseInstancePE databaseInstance)
     {
         assert sampleCodes != null : "Unspecified sample codes.";
         assert databaseInstance != null : "Unspecified database instance.";
 
         Criteria criteria = createDatabaseInstanceCriteria(databaseInstance);
-        addSampleCodesCriterion(criteria, sampleCodes);
+        addSampleCodesCriterion(criteria, sampleCodes, containerCodeOrNull);
         List<SamplePE> result = cast(criteria.list());
         if (operationLog.isDebugEnabled())
         {
@@ -245,13 +245,13 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
     }
 
     public final List<SamplePE> listByCodesAndGroup(final List<String> sampleCodes,
-            final GroupPE group)
+            final String containerCodeOrNull, final GroupPE group)
     {
         assert sampleCodes != null : "Unspecified sample codes.";
         assert group != null : "Unspecified space.";
 
         Criteria criteria = createGroupCriteria(group);
-        addSampleCodesCriterion(criteria, sampleCodes);
+        addSampleCodesCriterion(criteria, sampleCodes, containerCodeOrNull);
         List<SamplePE> result = cast(criteria.list());
         if (operationLog.isDebugEnabled())
         {
@@ -267,7 +267,7 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
 
     private SamplePE tryFindContainedSampleWithUniqueSubcode(Criteria criteria, String sampleCode)
     {
-        addContainedSampleCodeCriterion(criteria, sampleCode);
+        addContainedCodeCriterion(criteria, sampleCode);
         List<SamplePE> list = cast(criteria.list());
         return list.size() == 1 ? list.get(0) : null;
     }
@@ -290,32 +290,41 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
         return createFindCriteria(Restrictions.eq("group", group));
     }
 
-    private void addSampleCodesCriterion(Criteria criteria, List<String> sampleCodes)
+    private void addSampleCodesCriterion(Criteria criteria, List<String> sampleCodes,
+            String containerCodeOrNull)
     {
-        // no support for contained samples
-        criteria.add(Restrictions.in("code", sampleCodes));
-        criteria.add(Restrictions.isNull("container"));
+        List<String> convertedCodes = new ArrayList<String>();
+        for (String sampleCode : sampleCodes)
+        {
+            convertedCodes.add(CodeConverter.tryToDatabase(sampleCode));
+        }
+        criteria.add(Restrictions.in("code", convertedCodes));
+        addSampleContainerCriterion(criteria, containerCodeOrNull);
     }
 
-    private void addSampleCodeCriterion(Criteria criteria, String sampleCode)
+    private void addSampleContainerCriterion(Criteria criteria, String containerCodeOrNull)
     {
-        String[] sampleCodeTokens =
-                sampleCode.split(SampleIdentifier.CONTAINED_SAMPLE_CODE_SEPARARTOR_STRING);
-        if (sampleCodeTokens.length > 1)
+        if (containerCodeOrNull != null)
         {
-            final String containerCode = sampleCodeTokens[0];
-            final String code = sampleCodeTokens[1];
-            criteria.add(Restrictions.eq("code", CodeConverter.tryToDatabase(code)));
             criteria.createAlias("container", "c");
-            criteria.add(Restrictions.eq("c.code", CodeConverter.tryToDatabase(containerCode)));
+            criteria.add(Restrictions.eq("c.code", CodeConverter.tryToDatabase(containerCodeOrNull)));
         } else
         {
-            criteria.add(Restrictions.eq("code", CodeConverter.tryToDatabase(sampleCode)));
             criteria.add(Restrictions.isNull("container"));
         }
     }
 
-    private void addContainedSampleCodeCriterion(Criteria criteria, String sampleCode)
+    private void addSampleCodeCriterion(Criteria criteria, String sampleCode)
+    {
+        String[] sampleCodeTokens =
+                sampleCode.split(SampleIdentifier.CONTAINED_SAMPLE_CODE_SEPARARTOR_STRING);
+        String subCode = sampleCodeTokens.length > 1 ? sampleCodeTokens[1] : sampleCode;
+        String containerCodeOrNull = sampleCodeTokens.length > 1 ? sampleCodeTokens[0] : null;
+        criteria.add(Restrictions.eq("code", CodeConverter.tryToDatabase(subCode)));
+        addContainedCodeCriterion(criteria, containerCodeOrNull);
+    }
+
+    private void addContainedCodeCriterion(Criteria criteria, String sampleCode)
     {
         criteria.add(Restrictions.eq("code", CodeConverter.tryToDatabase(sampleCode)));
         criteria.add(Restrictions.isNotNull("container"));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
index 2e0478030174f9757b104ace09219b66eee77b6a..00626bd8a3cd7dbea8724d8e176d9a017aa322b8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
@@ -37,6 +37,8 @@ public class SampleIdentifier extends SampleOwnerIdentifier
 
     private String sampleSubCode;
 
+    private String containerCodeOrNull;
+
     private SampleIdentifier(final DatabaseInstanceIdentifier databaseInstanceIdentOrNull,
             final SpaceIdentifier spaceIdentOrNull, final String sampleCode)
     {
@@ -88,6 +90,11 @@ public class SampleIdentifier extends SampleOwnerIdentifier
         return sampleSubCode;
     }
 
+    public String getContainerCodeOrNull()
+    {
+        return containerCodeOrNull;
+    }
+
     /**
      * Returns an object that only contains the owner information of this sample identifier.
      * {@link #hashCode()} will be the same when called on two different samples with same owner.
@@ -111,6 +118,10 @@ public class SampleIdentifier extends SampleOwnerIdentifier
         {
             String[] sampleCodeTokens = sampleCode.split(CONTAINED_SAMPLE_CODE_SEPARARTOR_STRING);
             this.sampleSubCode = sampleCodeTokens[sampleCodeTokens.length - 1];
+            if (sampleCodeTokens.length > 1)
+            {
+                containerCodeOrNull = sampleCodeTokens[0];
+            }
         } else
         {
             this.sampleSubCode = sampleCode;