diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
index a39e7035be1bcff05d28a53f4015819d0eb55461..63dba29e61bd181ff24d796b5e05e45c55527026 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
@@ -29,8 +29,6 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SpaceWithProjectsAndRo
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 
 /**
- * 
- *
  * @author Franz-Josef Elmer
  */
 class GeneralInformationServiceLogger extends AbstractServerLogger implements
@@ -46,7 +44,7 @@ class GeneralInformationServiceLogger extends AbstractServerLogger implements
     {
         return null;
     }
-    
+
     public Map<String, Set<Role>> listNamedRoleSets(String sessionToken)
     {
         logAccess(sessionToken, "list-role-sets");
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
index f1b0f8ffb0d3909962c85d80976b8ab8512ebdc0..35008df44e2442d155c1007f24e1fc7b48e65a6a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
@@ -96,7 +96,7 @@ public interface ISampleListingQuery extends TransactionQuery, IPropertyListingQ
     /**
      * Returns the parent sample ids of the specified children sample ids in specified relationship.
      */
-    @Select(sql = "SELECT sample_id_child, sample_id_parent FROM sample_relationships "
+    @Select(sql = "SELECT * FROM sample_relationships "
             + "    WHERE relationship_id=?{1} AND sample_id_child = any(?{2})", parameterBindings =
         { TypeMapper.class/* default */, LongSetMapper.class }, fetchSize = FETCH_SIZE)
     public DataIterator<SampleRelationRecord> getParentRelations(long relationshipId,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleRelationRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleRelationRecord.java
index 89fa3b207fbd41dd5beff1d28c4a75fb8fcff618..8e8b1f99c137d9a524d3606708c8becccaeba8e0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleRelationRecord.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleRelationRecord.java
@@ -26,6 +26,8 @@ import ch.rinn.restrictions.Private;
 @Private
 public class SampleRelationRecord
 {
+    public long relationship_id;
+
     public long sample_id_parent;
 
     public long sample_id_child;
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingQueryTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingQueryTest.java
index 6391a3afd55d63b09f661e890e6f4e90c3541e44..5583da68839172ee60db1995c9eb1bd4c821ccc8 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingQueryTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingQueryTest.java
@@ -22,6 +22,9 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
+import it.unimi.dsi.fastutil.longs.LongSet;
 
 import java.sql.SQLException;
 import java.util.Arrays;
@@ -71,6 +74,12 @@ public class SampleListingQueryTest extends AbstractDAOTest
 
     private static final String SAMPLE_TYPE_CODE_CELL_PLATE = "CELL_PLATE";
 
+    private static final String DEFAULT_SPACE_CODE = "CISD";
+
+    private static final String DILUTION_PLATE_CODE_1 = "3V-123";
+
+    private static final String DILUTION_PLATE_CODE_2 = "3V-125";
+
     private long dbInstanceId;
 
     private DatabaseInstancePE dbInstance;
@@ -85,6 +94,12 @@ public class SampleListingQueryTest extends AbstractDAOTest
 
     private SamplePE sharedMasterPlate;
 
+    private SamplePE dilutionPlate1;
+
+    private SamplePE dilutionPlate2;
+
+    private long parentChildRelationshipTypeId;
+
     private ISampleListingQuery query;
 
     @BeforeClass(alwaysRun = true)
@@ -93,7 +108,9 @@ public class SampleListingQueryTest extends AbstractDAOTest
         SampleListerDAO sampleListerDAO = createSampleListerDAO(daoFactory);
         dbInstanceId = sampleListerDAO.getDatabaseInstanceId();
         dbInstance = daoFactory.getDatabaseInstanceDAO().getByTechId(new TechId(dbInstanceId));
-        group = daoFactory.getGroupDAO().tryFindGroupByCodeAndDatabaseInstance("CISD", dbInstance);
+        group =
+                daoFactory.getGroupDAO().tryFindGroupByCodeAndDatabaseInstance(DEFAULT_SPACE_CODE,
+                        dbInstance);
         groupId = group.getId();
         groupCode = group.getCode();
         masterPlateType =
@@ -102,7 +119,9 @@ public class SampleListingQueryTest extends AbstractDAOTest
         sharedMasterPlate =
                 daoFactory.getSampleDAO().tryFindByCodeAndDatabaseInstance(
                         SHARED_MASTER_PLATE_CODE, dbInstance);
+        assertEquals(SHARED_MASTER_PLATE_ID, sharedMasterPlate.getId().longValue());
         query = sampleListerDAO.getQuery();
+        parentChildRelationshipTypeId = query.getRelationshipTypeId("PARENT_CHILD", true);
     }
 
     @AfterClass(alwaysRun = true)
@@ -121,6 +140,74 @@ public class SampleListingQueryTest extends AbstractDAOTest
         return SampleListerDAO.create(daoFactory, query);
     }
 
+    @Test
+    public void testSampleCount()
+    {
+        assertEquals(1020, query.getSampleCount(dbInstanceId));
+    }
+
+    @Test
+    public void testGetRelationshipTypeId()
+    {
+        assertEquals(1, query.getRelationshipTypeId("PARENT_CHILD", true));
+        assertEquals(2, query.getRelationshipTypeId("PLATE_CONTROL_LAYOUT", true));
+        assertRelationshipTypeNotExists("FAKE_RELATIONSHIP", true);
+        assertRelationshipTypeNotExists("PARENT_CHILD", false);
+        assertRelationshipTypeNotExists("PLATE_CONTROL_LAYOUT", false);
+        assertRelationshipTypeNotExists("FAKE_RELATIONSHIP", false);
+    }
+
+    private void assertRelationshipTypeNotExists(String code, boolean internalNamespace)
+    {
+        try
+        {
+            long id = query.getRelationshipTypeId(code, internalNamespace);
+            fail("unexpected " + (internalNamespace ? "internal" : "user defined")
+                    + " relationship found with code " + code + " and id " + id);
+        } catch (NullPointerException e)
+        {
+        }
+    }
+
+    @Test
+    public void testGetParentRelations()
+    {
+        dilutionPlate1 =
+                daoFactory.getSampleDAO().tryFindByCodeAndGroup(DILUTION_PLATE_CODE_1, group);
+        dilutionPlate2 =
+                daoFactory.getSampleDAO().tryFindByCodeAndGroup(DILUTION_PLATE_CODE_2, group);
+        final int children1 = 2;
+        final int children2 = 6;
+        assertEquals(children1, dilutionPlate1.getGenerated().size());
+        assertEquals(children2, dilutionPlate2.getGenerated().size());
+        LongSet dilutionPlateIdSet = new LongOpenHashSet(new long[]
+            { dilutionPlate1.getId(), dilutionPlate2.getId() });
+        LongSet childrenIds =
+                new LongOpenHashSet(query.getChildrenIds(parentChildRelationshipTypeId,
+                        dilutionPlateIdSet));
+        assertEquals(8, childrenIds.size());
+        int sampleCount1 = 0;
+        int sampleCount2 = 0;
+        for (SampleRelationRecord sample : query.getParentRelations(parentChildRelationshipTypeId,
+                childrenIds))
+        {
+            assertEquals(parentChildRelationshipTypeId, sample.relationship_id);
+            if (dilutionPlate1.getId().equals(sample.sample_id_parent))
+            {
+                sampleCount1++;
+            } else if (dilutionPlate2.getId().equals(sample.sample_id_parent))
+            {
+                sampleCount2++;
+            } else
+            {
+                fail("unexpected sample parent id: " + sample.sample_id_parent + " for child id: "
+                        + sample.sample_id_child);
+            }
+        }
+        assertEquals(children1, sampleCount1);
+        assertEquals(children2, sampleCount2);
+    }
+
     @Test(groups = "slow")
     public void testQuerySamples()
     {
@@ -153,20 +240,6 @@ public class SampleListingQueryTest extends AbstractDAOTest
             {
                 assertEquals(msg, samplePE.getInvalidation().getId(), sample.inva_id);
             }
-            // FIXME
-            // if (samplePE.getGeneratedFrom() == null)
-            // {
-            // assertNull(msg, sample.samp_id_generated_from);
-            // } else
-            // {
-            // // Work around Hibernate peculiarity
-            // Long idGeneratedFrom = samplePE.getGeneratedFrom().getId();
-            // if (idGeneratedFrom == null)
-            // {
-            // idGeneratedFrom = HibernateUtils.getId(samplePE.getGeneratedFrom());
-            // }
-            // assertEquals(msg, idGeneratedFrom, sample.samp_id_generated_from);
-            // }
             if (samplePE.getContainer() == null)
             {
                 assertNull(msg, sample.samp_id_part_of);
@@ -208,11 +281,9 @@ public class SampleListingQueryTest extends AbstractDAOTest
         assertEquals(2, sample.pers_id_registerer);
         assertEquals(sampleTypeId, sample.saty_id);
         assertNotNull(sample.perm_id);
-        // assertNull(sample.samp_id_generated_from); FIXME
         assertNull(sample.samp_id_part_of);
 
         SampleRecord sample2 = findCode(samples, "3VCP1");
-        // assertNotNull(sample2.samp_id_generated_from); FIXME
         assertNull(sample2.samp_id_part_of);
     }
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorkerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorkerTest.java
index 1732f94794bf572f39d54d8e1a39ab7f0c019b54..7c3f36c28064a0a1a8abb345aae8a80049383efa 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorkerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorkerTest.java
@@ -16,7 +16,9 @@
 
 package ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
 import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
 import it.unimi.dsi.fastutil.longs.LongSet;
@@ -38,12 +40,22 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
  * Test cases for the {@link SampleListingWorker}.
  * 
  * @author Bernd Rinn
+ * @author Piotr Buczek
  */
 public class SampleListingWorkerTest extends AbstractDAOTest
 {
 
     private final String BASE_INDEX_URL = "baseIndexURL";
 
+    private final String SPACE_CODE = "CISD";
+
+    private final long CONTAINER_ID = 997L;
+
+    private final long PARENT_ID = 979L;
+
+    private final Long[] CHILDREN_IDS =
+        { 984L, 985L, 986L, 987L, 988L, 989L };
+
     private SampleListerDAO sampleListerDAO;
 
     private SecondaryEntityDAO secondaryDAO;
@@ -56,27 +68,49 @@ public class SampleListingWorkerTest extends AbstractDAOTest
     }
 
     @Test
-    public void testListSamplesByIdGroupNotNull()
+    public void testListSamplesBySpace()
+    {
+        final ListSampleCriteria baseCriteria = new ListSampleCriteria();
+        baseCriteria.setSpaceCode(SPACE_CODE);
+        baseCriteria.setIncludeSpace(true);
+        final ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(baseCriteria);
+        final SampleListingWorker worker =
+                SampleListingWorker.create(criteria, BASE_INDEX_URL, sampleListerDAO, secondaryDAO);
+        final List<Sample> list = worker.load();
+        assertTrue(list.size() > 0);
+        for (Sample s : list)
+        {
+            checkSpace(s);
+            if (Arrays.binarySearch(CHILDREN_IDS, s.getId()) >= 0)
+            {
+                checkGeneratedFrom(s);
+            }
+        }
+    }
+
+    @Test
+    public void testListSamplesById()
     {
         final LongSet sampleIds = new LongOpenHashSet();
-        sampleIds.addAll(Arrays.asList(1L, 2L, 3L));
+        sampleIds.addAll(Arrays.asList(CHILDREN_IDS));
         final ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(sampleIds);
         final SampleListingWorker worker =
                 SampleListingWorker.create(criteria, BASE_INDEX_URL, sampleListerDAO, secondaryDAO);
         final List<Sample> list = worker.load();
-        assertTrue(list.size() > 0);
+        assertEquals(CHILDREN_IDS.length, list.size());
         for (Sample s : list)
         {
-            assertNotNull("ID:" + s.getId(), s.getSpace());
-            assertNotNull("ID:" + s.getId(), s.getSpace().getInstance());
+            assertTrue(Arrays.binarySearch(CHILDREN_IDS, s.getId()) >= 0);
+            checkSpace(s);
+            checkGeneratedFrom(s);
         }
     }
 
     @Test
-    public void testListSamplesForContainerGroupNotNull()
+    public void testListSamplesForContainer()
     {
         final ListSampleCriteria baseCriteria =
-                ListSampleCriteria.createForContainer(new TechId(997L));
+                ListSampleCriteria.createForContainer(new TechId(CONTAINER_ID));
         final ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(baseCriteria);
         final SampleListingWorker worker =
                 SampleListingWorker.create(criteria, BASE_INDEX_URL, sampleListerDAO, secondaryDAO);
@@ -84,16 +118,36 @@ public class SampleListingWorkerTest extends AbstractDAOTest
         assertTrue(list.size() > 0);
         for (Sample s : list)
         {
-            assertNotNull("ID:" + s.getId(), s.getSpace());
-            assertNotNull("ID:" + s.getId(), s.getSpace().getInstance());
+            checkSpace(s);
+            assertNotNull("ID:" + s.getId(), s.getContainer());
+            assertEquals("ID:" + s.getId(), CONTAINER_ID, s.getContainer().getId().longValue());
         }
     }
 
     @Test
-    public void testListSamplesForExperimentGroupNotNull()
+    public void testListSamplesForParent()
     {
         final ListSampleCriteria baseCriteria =
-                ListSampleCriteria.createForExperiment(new TechId(2L));
+                ListSampleCriteria.createForParent(new TechId(PARENT_ID));
+        final ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(baseCriteria);
+        final SampleListingWorker worker =
+                SampleListingWorker.create(criteria, BASE_INDEX_URL, sampleListerDAO, secondaryDAO);
+        final List<Sample> list = worker.load();
+        assertEquals(CHILDREN_IDS.length, list.size());
+        for (Sample s : list)
+        {
+            assertTrue(Arrays.binarySearch(CHILDREN_IDS, s.getId()) >= 0);
+            checkSpace(s);
+            checkGeneratedFrom(s);
+        }
+    }
+
+    @Test
+    public void testListSamplesForExperiment()
+    {
+        final long expId = 2L;
+        final ListSampleCriteria baseCriteria =
+                ListSampleCriteria.createForExperiment(new TechId(expId));
         final ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(baseCriteria);
         final SampleListingWorker worker =
                 SampleListingWorker.create(criteria, BASE_INDEX_URL, sampleListerDAO, secondaryDAO);
@@ -101,8 +155,24 @@ public class SampleListingWorkerTest extends AbstractDAOTest
         assertTrue(list.size() > 0);
         for (Sample s : list)
         {
-            assertNotNull("ID:" + s.getId(), s.getSpace());
-            assertNotNull("ID:" + s.getId(), s.getSpace().getInstance());
+            checkSpace(s);
+            assertNotNull("ID:" + s.getId(), s.getExperiment());
+            assertEquals("ID:" + s.getId(), expId, s.getExperiment().getId().longValue());
         }
     }
+
+    private void checkSpace(Sample s)
+    {
+        assertNotNull("ID:" + s.getId(), s.getSpace());
+        assertNotNull("ID:" + s.getId(), s.getSpace().getInstance());
+        assertEquals("ID:" + s.getId(), SPACE_CODE, s.getSpace().getCode());
+    }
+
+    private void checkGeneratedFrom(Sample s)
+    {
+        assertNotNull("ID:" + s.getId(), s.getGeneratedFrom());
+        assertEquals("ID:" + s.getId(), PARENT_ID, s.getGeneratedFrom().getId().longValue());
+        assertNotNull("ID:" + s.getId(), s.getGeneratedFrom().getGeneratedFrom());
+        assertNull("ID:" + s.getId(), s.getGeneratedFrom().getGeneratedFrom().getGeneratedFrom());
+    }
 }