diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBOTest.java
index 7afbbd93c8158757598117f1a458247068a69ba7..38f4c1c61a22819d0b966bae6aec242465f819d9 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentBOTest.java
@@ -47,6 +47,7 @@ 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.ExperimentTypePropertyTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSession;
 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;
@@ -472,6 +473,49 @@ public final class ExperimentBOTest extends AbstractBOTest
         assertEquals(newProject.getSpace(), assignedSample.getSpace());
     }
 
+    @Test
+    public final void testEditSamples()
+    {
+        // we test if this sample will stay assigned to the experiment if it was assigned before
+        SamplePE untouchedSample = createSampleWithCode("untouchedSample");
+        // we test unasignment of this sample from the experiment
+        SamplePE unassignedSample = createSampleWithCode("unassignedSample");
+        // we test if this sample will be assigned to the experiment
+        SamplePE assignedSample = createSampleWithCode("assignedSample");
+
+        final ExperimentIdentifier identifier = CommonTestUtils.createExperimentIdentifier();
+        final ExperimentPE exp = CommonTestUtils.createExperiment(identifier);
+        exp.setSamples(Arrays.asList(untouchedSample, unassignedSample));
+
+        prepareLoadExperimentByIdentifier(identifier, exp);
+        prepareTryFindSample(exp.getProject().getSpace(), assignedSample.getCode(), assignedSample);
+        prepareNoDatasetsFound();
+        final ExperimentBO expBO = loadExperiment(identifier, exp);
+
+        String[] editedSamples = new String[]
+            { untouchedSample.getCode(), assignedSample.getCode() };
+        expBO.setExperimentSamples(editedSamples);
+        assertEquals(exp, untouchedSample.getExperiment());
+    }
+
+    private void prepareNoDatasetsFound()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(dataDAO).hasDataSet((with(any(SamplePE.class))));
+                    will(returnValue(false));
+
+                    one(relationshipService).assignSampleToExperiment(
+                            with(any(IAuthSession.class)), with(any(SamplePE.class)),
+                            with(any(ExperimentPE.class)));
+
+                    one(relationshipService).unassignSampleFromExperiment(
+                            with(any(IAuthSession.class)), with(any(SamplePE.class)));
+                }
+            });
+    }
+
     @Test
     public final void testEditSamplesAddingAssignedSampleFails()
     {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBOTest.java
index df809c833fb91bef234a3d5a62a059172a558b8c..35ccac9562bbef606f3f7c5d307eed9162bfb8f7 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBOTest.java
@@ -49,6 +49,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSession;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
@@ -61,6 +62,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceId
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.IdentifierHelper;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
 
 /**
  * Test cases for corresponding {@link SampleBO} class.
@@ -377,6 +379,156 @@ public final class SampleBOTest extends AbstractBOTest
         createSampleBO().define(newSample);
     }
 
+    @SuppressWarnings("unchecked")
+    @Test
+    public final void testDetachFromExperiment()
+    {
+        final SamplePE sample = createAnySample();
+        sample.setExperiment(new ExperimentPE());
+        sample.setId(SAMPLE_TECH_ID.getId());
+
+        prepareExperimentUpdateOnly(sample);
+        context.checking(new Expectations()
+            {
+                {
+                    one(entityOperationChecker).assertInstanceSampleUpdateAllowed(
+                            with(any(IAuthSession.class)), with(any(List.class)));
+                    one(relationshipService).unassignSampleFromExperiment(
+                            with(any(IAuthSession.class)), with(any(SamplePE.class)));
+                }
+            });
+
+        ExperimentIdentifier experimentIdentifier = null;
+
+        updateSampleExperiment(SAMPLE_TECH_ID, sample, experimentIdentifier);
+        context.assertIsSatisfied();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public final void testDetachFromExperimentWithDatasetsFails()
+    {
+        final SamplePE sample = createAnySample();
+        sample.setExperiment(new ExperimentPE());
+        sample.setId(SAMPLE_TECH_ID.getId());
+
+        prepareTryToLoadOfSampleWithId(sample);
+        prepareNoPropertiesToUpdate(sample);
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(dataDAO).hasDataSet(with(sample));
+                    will(returnValue(true));
+                    one(entityOperationChecker).assertInstanceSampleUpdateAllowed(
+                            with(any(IAuthSession.class)), with(any(List.class)));
+                }
+            });
+        ExperimentIdentifier experimentIdentifier = null;
+        String errorMsg =
+                "Cannot detach the sample 'CODE:/XX' from the experiment because there are already datasets attached to the sample.";
+        try
+        {
+            updateSampleExperiment(SAMPLE_TECH_ID, sample, experimentIdentifier);
+        } catch (UserFailureException e)
+        {
+            assertEquals(errorMsg, e.getMessage());
+            return;
+        }
+        fail("Following exception expected: " + errorMsg);
+    }
+
+    @Test
+    public final void testEditSampleChangeGroupToShared()
+    {
+        final SamplePE sample = createSample("sampleCode", EXAMPLE_GROUP);
+
+        Date now = new Date();
+        sample.setModificationDate(now);
+
+        prepareTryToLoadOfSampleWithId(sample);
+        prepareNoPropertiesToUpdate(sample);
+        context.checking(new Expectations()
+            {
+                {
+
+                    allowing(daoFactory).getHomeDatabaseInstance();
+                    will(returnValue(EXAMPLE_DATABASE_INSTANCE));
+
+                    allowing(dataDAO).hasDataSet(with(sample));
+                    will(returnValue(false));
+
+                    allowing(relationshipService).unassignSampleFromExperiment(
+                            with(any(IAuthSession.class)), with(any(SamplePE.class)));
+
+                    one(relationshipService).shareSample(with(any(IAuthSession.class)),
+                            with(any(SamplePE.class)));
+                }
+            });
+        String newSampleIdentifierWithoutDb = "/" + sample.getCode();
+        assertNotNull(sample.getSpace());
+        createSampleBO().update(
+                new SampleUpdatesDTO(SAMPLE_TECH_ID, null, null, Collections
+                        .<NewAttachment> emptyList(), now, SampleIdentifierFactory
+                        .parse(newSampleIdentifierWithoutDb), null, null));
+        context.assertIsSatisfied();
+
+    }
+
+    @Test
+    public final void testEditExperiment()
+    {
+        final ProjectPE project = createProject();
+        // create experiment which we will attach the sample
+        final ExperimentPE experimentToAttach = new ExperimentPE();
+        experimentToAttach.setCode("exp1");
+        experimentToAttach.setProject(project);
+        final ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier();
+        experimentIdentifier.setExperimentCode("exp1");
+        experimentIdentifier.setProjectCode(project.getCode());
+        experimentIdentifier.setSpaceCode(project.getSpace().getCode());
+        experimentIdentifier.setDatabaseInstanceCode(project.getSpace().getDatabaseInstance()
+                .getCode());
+
+        // create a sample already attached to an experiment
+        final ExperimentPE sampleExperiment = new ExperimentPE();
+        sampleExperiment.setCode("exp2");
+        sampleExperiment.setProject(project);
+        final SamplePE sample = new SamplePE();
+        sample.setId(SAMPLE_TECH_ID.getId());
+        sample.setCode("sampleCode");
+        sample.setExperiment(sampleExperiment);
+        sample.setSpace(EXAMPLE_GROUP);
+        sample.setSampleType(createSampleTypePE(SAMPLE_TYPE));
+
+        Date now = new Date();
+        sample.setModificationDate(now);
+
+        prepareTryToLoadOfSampleWithId(sample);
+        prepareNoPropertiesToUpdate(sample);
+        context.checking(new Expectations()
+            {
+                {
+                    one(projectDAO).tryFindProject(experimentIdentifier.getDatabaseInstanceCode(),
+                            experimentIdentifier.getSpaceCode(),
+                            experimentIdentifier.getProjectCode());
+                    will(returnValue(project));
+
+                    one(experimentDAO).tryFindByCodeAndProject(project,
+                            experimentIdentifier.getExperimentCode());
+                    will(returnValue(experimentToAttach));
+
+                    one(relationshipService).assignSampleToExperiment(
+                            with(any(IAuthSession.class)), with(any(SamplePE.class)),
+                            with(any(ExperimentPE.class)));
+                }
+            });
+        createSampleBO().update(
+                new SampleUpdatesDTO(SAMPLE_TECH_ID, null, experimentIdentifier, Collections
+                        .<NewAttachment> emptyList(), now, null, null, null));
+
+        context.assertIsSatisfied();
+    }
+
     @Test
     public final void testEditSampleParent()
     {
@@ -634,6 +786,43 @@ public final class SampleBOTest extends AbstractBOTest
         context.assertIsSatisfied();
     }
 
+    @Test
+    public final void testEditSampleNoExperimentForSampleWithDatasets()
+    {
+        final SamplePE sample = createSample("sampleCode", EXAMPLE_GROUP);
+        sample.setExperiment(new ExperimentPE());
+
+        Date now = new Date();
+        sample.setModificationDate(now);
+
+        prepareTryToLoadOfSampleWithId(sample);
+        prepareNoPropertiesToUpdate(sample);
+        context.checking(new Expectations()
+            {
+                {
+
+                    allowing(dataDAO).hasDataSet(with(sample));
+                    will(returnValue(true));
+                }
+            });
+        boolean exceptionThrown = false;
+        try
+        {
+            createSampleBO().update(
+                    new SampleUpdatesDTO(SAMPLE_TECH_ID, null, null, Collections
+                            .<NewAttachment> emptyList(), now, null, null, null));
+        } catch (UserFailureException ex)
+        {
+            exceptionThrown = true;
+            assertTrue(ex
+                    .getMessage()
+                    .contains(
+                            "from the experiment because there are already datasets attached to the sample"));
+        }
+        assertTrue(exceptionThrown);
+        context.assertIsSatisfied();
+    }
+
     @Test
     public final void testEditStaleSampleFails()
     {