diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
index fec9af91f5251c427ff9d2d3730afe78b8738571..c31727586ccd67baa29a6231f98ea4192be12884 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
@@ -23,7 +23,6 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.util.SampleUtils;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.RelationshipUtils;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.DAOFactory;
 import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
-import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetRelationshipPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
@@ -34,6 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.RelationshipTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleRelationshipPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
 
 /**
  * The unique {@link IRelationshipService} implementation.
@@ -95,11 +95,6 @@ public class RelationshipService implements IRelationshipService
         sample.setExperiment(experiment);
         RelationshipUtils.updateModificationDateAndModifier(sample, session);
         RelationshipUtils.updateModificationDateAndModifier(experiment, session);
-
-        for (DataPE dataset : sample.getDatasets())
-        {
-            service.assignDataSetToExperiment(session, dataset, experiment);
-        }
     }
 
     @Override
@@ -150,7 +145,7 @@ public class RelationshipService implements IRelationshipService
     public void assignDataSetToSample(IAuthSession session, DataPE data, SamplePE sample)
     {
         SamplePE currentSample = data.tryGetSample();
-        if (equalEntities(currentSample, sample))
+        if (EntityHelper.equalEntities(currentSample, sample))
         {
             return;
         }
@@ -277,16 +272,4 @@ public class RelationshipService implements IRelationshipService
         return RelationshipUtils.getParentChildRelationshipType(daoFactory.getRelationshipTypeDAO());
     }
 
-    private static <T extends IIdHolder >boolean equalEntities(T entity1OrNull, T entity2OrNull)
-    {
-        Long id1 = getIdOrNull(entity1OrNull);
-        Long id2 = getIdOrNull(entity2OrNull);
-        return id1 == null ? id1 == id2 : id1.equals(id2);
-    }
-
-    private static Long getIdOrNull(IIdHolder idHolderOrNull)
-    {
-        return idHolderOrNull == null ? null : idHolderOrNull.getId();
-    }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
index 8ea60c974d94032e9e25544463ace9be0e66bdd3..215d99eb1e65709e39f400bc7a3fc2c5a8d3fcf3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
@@ -87,6 +87,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityWithMetaprojects;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IModifierAndModificationDateBean;
@@ -773,4 +774,32 @@ abstract class AbstractBusinessObject implements IDAOFactory
         return dataDAO.hasDataSet(sample);
     }
 
+    protected void assignSampleAndRelatedDataSetsToExperiment(SamplePE sample, ExperimentPE newExperiment)
+    {
+        NewDataSetToSampleExperimentAssignmentManager assignmentManager 
+                = new NewDataSetToSampleExperimentAssignmentManager(dataSetTypeChecker);
+        ExperimentPE previousSampleExperiment = sample.getExperiment();
+        if (previousSampleExperiment != null)
+        {
+            for (DataPE dataSet : previousSampleExperiment.getDataSets())
+            {
+                assignmentManager.assignDataSetAndRelatedComponents(dataSet, null, newExperiment);
+            }
+        }
+        for (DataPE dataSet : sample.getDatasets())
+        {
+            assignmentManager.assignDataSetAndRelatedComponents(dataSet, sample, newExperiment);
+        }
+        relationshipService.assignSampleToExperiment(session, sample, newExperiment);
+        assignmentManager.performAssignment(relationshipService, session);
+    }
+
+    protected void assignDataSetToSampleAndExperiment(DataPE data, SamplePE newSample, ExperimentPE experiment)
+    {
+        NewDataSetToSampleExperimentAssignmentManager assignmentManager 
+                = new NewDataSetToSampleExperimentAssignmentManager(dataSetTypeChecker);
+        assignmentManager.assignDataSetAndRelatedComponents(data, newSample, experiment);
+        assignmentManager.performAssignment(relationshipService, session);
+    }
+    
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractDataSetBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractDataSetBusinessObject.java
index 33617ecede6802427a0c18b4e9c25ee06814122c..6ef2a6e726095cbe7b0b7abd1c424ca6b487350f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractDataSetBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractDataSetBusinessObject.java
@@ -31,10 +31,10 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
 import ch.systemsx.cisd.openbis.generic.server.business.IServiceConversationClientManagerLocal;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.util.DataSetTypeWithoutExperimentChecker;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.util.SampleUtils;
 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.IEntityPropertiesConverter;
-import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 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.DataSetRelationshipPE;
@@ -111,97 +111,11 @@ public abstract class AbstractDataSetBusinessObject extends AbstractSampleIdenti
         }
         if (newSample.getSpace() == null)
         {
-            throw createWrongSampleException(data, newSample, "the new sample is shared");
+            throw SampleUtils.createWrongSampleException(data, newSample, "the new sample is shared");
         }
         assignDataSetToSampleAndExperiment(data, newSample, newSample.getExperiment());
     }
 
-    private void assignDataSetToSampleAndExperiment(DataPE data, SamplePE newSample, ExperimentPE experiment)
-    {
-        List<DataSetSampleExperiment> assignments = new ArrayList<DataSetSampleExperiment>();
-        gatherNewAssigments(assignments, data, data, newSample, experiment);
-        for (DataSetSampleExperiment assignment : assignments)
-        {
-            assignment.assignDataSet(relationshipService, session);
-        }
-    }
-    
-    private void gatherNewAssigments(List<DataSetSampleExperiment> assignments, 
-            DataPE dataSet, DataPE rootDataSet, SamplePE sample, ExperimentPE experiment)
-    {
-        String dataSetTypeCode = dataSet.getDataSetType().getCode();
-        if (experiment == null && dataSetTypeChecker.isDataSetTypeWithoutExperiment(dataSetTypeCode) == false)
-        {
-            throw createWrongSampleException(dataSet, sample,
-                    "the new sample is not connected to any experiment and the data set type ("
-                            + dataSetTypeCode + ") doesn't match one of the following regular expressions: "
-                            + dataSetTypeChecker.getRegularExpressions());
-        }
-        if (rootDataSet == dataSet)
-        {
-            assignments.add(new DataSetSampleExperiment(dataSet, sample, experiment));
-        }
-        SamplePE rootSample = rootDataSet.tryGetSample();
-        ExperimentPE rootExperiment = getExperimentOf(rootDataSet);
-        List<DataPE> components = dataSet.getContainedDataSets();
-        for (DataPE component : components)
-        {
-            SamplePE componentSample = component.tryGetSample();
-            ExperimentPE componentExperiment = getExperimentOf(component);
-            if ((equalEntities(rootSample, componentSample) || componentSample == null)
-                    && equalEntities(rootExperiment, componentExperiment))
-            {
-                SamplePE newSample = componentSample == null && experiment != null? null : sample;
-                assignments.add(new DataSetSampleExperiment(component, newSample, experiment));
-                gatherNewAssigments(assignments, component, rootDataSet, sample, experiment);
-            }
-        }
-    }
-    
-    private ExperimentPE getExperimentOf(DataPE data)
-    {
-        SamplePE sample = data.tryGetSample();
-        return sample == null ? data.getExperiment() : sample.getExperiment();
-    }
-    
-    private static <T extends IIdHolder >boolean equalEntities(T entity1OrNull, T entity2OrNull)
-    {
-        Long id1 = getIdOrNull(entity1OrNull);
-        Long id2 = getIdOrNull(entity2OrNull);
-        return id1 == null ? id1 == id2 : id1.equals(id2);
-    }
-
-    private static Long getIdOrNull(IIdHolder idHolderOrNull)
-    {
-        return idHolderOrNull == null ? null : idHolderOrNull.getId();
-    }
-
-    private static final class DataSetSampleExperiment
-    {
-        private DataPE dataSet;
-        private SamplePE sample;
-        private ExperimentPE experiment;
-
-        DataSetSampleExperiment(DataPE dataSet, SamplePE sample, ExperimentPE experiment)
-        {
-            this.dataSet = dataSet;
-            this.sample = sample;
-            this.experiment = experiment;
-        }
-
-        public void assignDataSet(IRelationshipService relationshipService, Session session)
-        {
-            if (equalEntities(dataSet.tryGetSample(), sample) == false)
-            {
-                relationshipService.assignDataSetToSample(session, dataSet, sample);
-            }
-            if (equalEntities(dataSet.getExperiment(), experiment) == false)
-            {
-                relationshipService.assignDataSetToExperiment(session, dataSet, experiment);
-            }
-        }
-    }
-
     protected void updateExperiment(DataPE data, ExperimentIdentifier experimentIdentifier)
     {
         assert experimentIdentifier != null;
@@ -534,14 +448,6 @@ public abstract class AbstractDataSetBusinessObject extends AbstractSampleIdenti
         return new LinkedHashSet<String>(objects); // keep the ordering
     }
 
-    private UserFailureException createWrongSampleException(DataPE data, SamplePE sample,
-            String reason)
-    {
-        return UserFailureException.fromTemplate(
-                "The dataset '%s' cannot be connected to the sample '%s'" + " because %s.",
-                data.getCode(), sample.getIdentifier(), reason);
-    }
-
     public IRelationshipService getRelationshipService()
     {
         return relationshipService;
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 020034c7cb1e6874f23d600640bc1721a50b7074..276320ff2bfd5001af0ca3404c963ef2d535466d 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
@@ -436,7 +436,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
             Map<EntityTypePE, List<EntityTypePropertyTypePE>> cacheOrNull, boolean spaceUpdated)
     {
         checkPropertiesBusinessRules(sample, cacheOrNull);
-        checkExperimentBusinessRules(dataDAO, sample);
+        checkExperimentBusinessRules(sample);
         checkParentBusinessRules(sample);
         checkContainerBusinessRules(sample);
     }
@@ -455,23 +455,16 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         }
     }
 
-    protected void checkExperimentBusinessRules(IDataDAO dataDAO, SamplePE sample)
+    protected void checkExperimentBusinessRules(SamplePE sample)
     {
-        final boolean hasDatasets = hasDatasets(dataDAO, sample);
-        ExperimentPE experiment = sample.getExperiment();
-        if (hasDatasets && experiment == null)
-        {
-            throw UserFailureException.fromTemplate(
-                    "Cannot detach the sample '%s' from the experiment "
-                            + "because there are already datasets attached to the sample.",
-                    sample.getIdentifier());
-        }
-        if (hasDatasets && sample.getSpace() == null)
+//        checkSampleWithoutDatasets(sample);
+        if (hasDatasets(sample) && sample.getSpace() == null)
         {
             throw UserFailureException.fromTemplate("Cannot detach the sample '%s' from the space "
                     + "because there are already datasets attached to the sample.",
                     sample.getIdentifier());
         }
+        ExperimentPE experiment = sample.getExperiment();
         if (experiment != null
                 && (sample.getSpace() == null || experiment.getProject().getSpace()
                         .equals(sample.getSpace()) == false))
@@ -494,11 +487,11 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         SampleGenericBusinessRules.assertValidComponents(sample);
     }
 
-    private boolean hasDatasets(IDataDAO dataDAO, SamplePE sample)
+    private boolean hasDatasets(SamplePE sample)
     {
         // If we just added new data sets in this BO, they won't have data sets, so no need to
         // check.
-        return (onlyNewSamples == false) && hasDatasets2(dataDAO, sample);
+        return (onlyNewSamples == false) && hasDatasets2(getDataDAO(), sample);
     }
 
     protected boolean updateSpace(SamplePE sample, SampleIdentifier sampleOwnerIdentifier,
@@ -539,18 +532,12 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
             return;
         }
 
-        if (expIdentifierOrNull != null)
-        {
-            changeExperiment(sample, expIdentifierOrNull, experimentCacheOrNull);
-        } else
-        {
-            removeFromExperiment(sample);
-        }
+        changeExperiment(sample, expIdentifierOrNull, experimentCacheOrNull);
     }
 
     private void removeFromExperiment(SamplePE sample)
     {
-        if (hasDatasets(getDataDAO(), sample))
+        if (hasDatasets(sample))
         {
             throw UserFailureException.fromTemplate(
                     "Cannot detach the sample '%s' from the experiment "
@@ -561,19 +548,19 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         relationshipService.unassignSampleFromExperiment(session, sample);
     }
 
-    private void changeExperiment(SamplePE sample, ExperimentIdentifier identifier,
+    private void changeExperiment(SamplePE sample, ExperimentIdentifier identifierOrNull,
             Map<String, ExperimentPE> experimentCacheOrNull)
     {
-        ExperimentPE newExperiment =
-                tryFindExperiment(experimentCacheOrNull, identifier.toString(), null);
+        ExperimentPE newExperiment = identifierOrNull == null ? null :
+                tryFindExperiment(experimentCacheOrNull, identifierOrNull.toString(), null);
         if (isExperimentUnchanged(newExperiment, sample.getExperiment()))
         {
             return;
         }
-        ensureExperimentIsValid(identifier, newExperiment, sample);
+        ensureExperimentIsValid(identifierOrNull, newExperiment, sample);
         ensureSampleAttachableToExperiment(sample);
 
-        relationshipService.assignSampleToExperiment(session, sample, newExperiment);
+        assignSampleAndRelatedDataSetsToExperiment(sample, newExperiment);
     }
 
     private void ensureSampleAttachableToExperiment(SamplePE sample)
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 d40d6442708b3154aaccd769f6e911aefa1ae5a2..38d826226cdd9daa12f92d740dc0f9ed620a15f1 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
@@ -534,7 +534,7 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
     {
         for (SamplePE sample : samples)
         {
-            relationshipService.assignSampleToExperiment(session, sample, experiment);
+            assignSampleAndRelatedDataSetsToExperiment(sample, experiment);
         }
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/NewDataSetToSampleExperimentManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/NewDataSetToSampleExperimentManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..fffe6fcd66f37292da1e9a42fb40b087d4d1cf64
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/NewDataSetToSampleExperimentManager.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server.business.bo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.util.DataSetTypeWithoutExperimentChecker;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.util.SampleUtils;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class NewDataSetToSampleExperimentAssignmentManager
+{
+    private final DataSetTypeWithoutExperimentChecker dataSetTypeChecker;
+    private final List<DataSetSampleExperiment> assignments = new ArrayList<DataSetSampleExperiment>();
+    
+    NewDataSetToSampleExperimentAssignmentManager(DataSetTypeWithoutExperimentChecker dataSetTypeChecker)
+    {
+        this.dataSetTypeChecker = dataSetTypeChecker;
+    }
+    
+    void performAssignment(IRelationshipService relationshipService, Session session)
+    {
+        for (DataSetSampleExperiment assignment : assignments)
+        {
+            assignment.assignDataSet(relationshipService, session);
+        }
+    }
+
+    void assignDataSetAndRelatedComponents(DataPE dataSet, SamplePE sample, ExperimentPE experiment)
+    {
+        assignDataSetAndRelatedComponents(dataSet, dataSet, sample, experiment);
+    }
+    
+    private void assignDataSetAndRelatedComponents(DataPE dataSet, DataPE rootDataSet, SamplePE sample, ExperimentPE experiment)
+    {
+        String dataSetTypeCode = dataSet.getDataSetType().getCode();
+        if (experiment == null && dataSetTypeChecker.isDataSetTypeWithoutExperiment(dataSetTypeCode) == false)
+        {
+            throw SampleUtils.createWrongSampleException(dataSet, sample,
+                    "the new sample is not connected to any experiment and the data set type ("
+                            + dataSetTypeCode + ") doesn't match one of the following regular expressions: "
+                            + dataSetTypeChecker.getRegularExpressions());
+        }
+        if (rootDataSet == dataSet)
+        {
+            assignments.add(new DataSetSampleExperiment(dataSet, sample, experiment));
+        }
+        SamplePE rootSample = rootDataSet.tryGetSample();
+        ExperimentPE rootExperiment = getExperimentOf(rootDataSet);
+        List<DataPE> components = dataSet.getContainedDataSets();
+        for (DataPE component : components)
+        {
+            SamplePE componentSample = component.tryGetSample();
+            ExperimentPE componentExperiment = getExperimentOf(component);
+            if ((EntityHelper.equalEntities(rootSample, componentSample) || componentSample == null)
+                    && EntityHelper.equalEntities(rootExperiment, componentExperiment))
+            {
+                SamplePE newSample = componentSample == null && experiment != null? null : sample;
+                assignments.add(new DataSetSampleExperiment(component, newSample, experiment));
+                assignDataSetAndRelatedComponents(component, rootDataSet, sample, experiment);
+            }
+        }
+    }
+    
+    private ExperimentPE getExperimentOf(DataPE data)
+    {
+        SamplePE sample = data.tryGetSample();
+        return sample == null ? data.getExperiment() : sample.getExperiment();
+    }
+
+    private static class DataSetSampleExperiment
+    {
+        private DataPE dataSet;
+        private SamplePE sample;
+        private ExperimentPE experiment;
+
+        DataSetSampleExperiment(DataPE dataSet, SamplePE sample, ExperimentPE experiment)
+        {
+            this.dataSet = dataSet;
+            this.sample = sample;
+            this.experiment = experiment;
+        }
+
+        void assignDataSet(IRelationshipService relationshipService, Session session)
+        {
+            if (EntityHelper.equalEntities(dataSet.tryGetSample(), sample) == false)
+            {
+                relationshipService.assignDataSetToSample(session, dataSet, sample);
+            }
+            if (EntityHelper.equalEntities(dataSet.getExperiment(), experiment) == false)
+            {
+                relationshipService.assignDataSetToExperiment(session, dataSet, experiment);
+            }
+        }
+    }}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
index 722b96310283f1e7ab874a68782a6439c17c5846..47ccded11f3e20d27cb79d29bbfbbe761a007b61 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
@@ -240,7 +240,7 @@ public final class SampleBO extends AbstractSampleBusinessObject implements ISam
         checkSampleUnused(sample);
         checkSampleWithoutDatasets(sample);
 
-        this.relationshipService.assignSampleToExperiment(session, sample, experiment);
+        assignSampleAndRelatedDataSetsToExperiment(sample, experiment);
         try
         {
             getSampleDAO().updateSample(sample, findPerson());
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 37bc0dd5f7bda56c61ba91903f581811f4510e64..699c943a71d0d09c66d81d0d40365b9abbc78b40 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
@@ -280,7 +280,7 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I
         {
             updateSpace(sample, updates.getSampleIdentifier(), sampleOwnerCache);
             updateExperiment(sample, updates.getExperimentIdentifierOrNull(), experimentCache);
-            checkExperimentBusinessRules(getDataDAO(), sample);
+            checkExperimentBusinessRules(sample);
         }
         if (details.isParentsUpdateRequested())
         {
@@ -333,7 +333,7 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I
         if (updates.isUpdateExperimentLink())
         {
             updateExperiment(sample, updates.getExperimentIdentifierOrNull(), experimentCache);
-            checkExperimentBusinessRules(getDataDAO(), sample);
+            checkExperimentBusinessRules(sample);
         }
 
         boolean parentsUpdated = updateParents(sample, updates);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/SampleUtils.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/SampleUtils.java
index 768247cc8464e7b9223e3f1768ad92df44b0f530..217030893671bb9d546ed30b32b557c9674bd1ec 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/SampleUtils.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/SampleUtils.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.server.business.bo.util;
 
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
@@ -37,4 +39,12 @@ public class SampleUtils
         }
     }
 
+    public static UserFailureException createWrongSampleException(DataPE data, SamplePE sample,
+            String reason)
+    {
+        return UserFailureException.fromTemplate(
+                "The dataset '%s' cannot be connected to the sample '%s' because %s.",
+                data.getCode(), sample.getIdentifier(), reason);
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
index bd673f98d1771d29a71048dfe9f23f095c3c44a6..682016be8d3363d8e2a1dd269f493bef4e9bd420 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
@@ -25,6 +25,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
@@ -53,6 +54,21 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFa
  */
 public class EntityHelper
 {
+    /**
+     * Returns <code>true</code> if both entities are <code>null</code> or have the same id (which could be <code>null</code>).
+     */
+    public static <T extends IIdHolder >boolean equalEntities(T entity1OrNull, T entity2OrNull)
+    {
+        Long id1 = getIdOrNull(entity1OrNull);
+        Long id2 = getIdOrNull(entity2OrNull);
+        return id1 == null ? id1 == id2 : id1.equals(id2);
+    }
+
+    private static Long getIdOrNull(IIdHolder idHolderOrNull)
+    {
+        return idHolderOrNull == null ? null : idHolderOrNull.getId();
+    }
+    
     /**
      * Creates {@link EntityType} appropriate for given {@link EntityKind}.
      */