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 cd657659ec08a62c5ffbbe8fcdbc907be8fce6d1..a3899fbe09ae95d4535155937f636c1cf211d62e 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
@@ -353,9 +353,11 @@ public final class ExperimentBO extends AbstractBusinessObject implements IExper
     public final void addAttachment(final AttachmentPE experimentAttachment)
     {
         assert experiment != null : "no experiment has been loaded";
-        experimentAttachment.setRegistrator(findPerson());
+        PersonPE user = findPerson();
+        experimentAttachment.setRegistrator(user);
         escapeFileName(experimentAttachment);
         attachments.add(experimentAttachment);
+        RelationshipUtils.updateModificationDateAndModifier(experiment, user);
     }
 
     private void escapeFileName(final AttachmentPE attachment)
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 be444b4859fc14a29f71042a6319f32449de8260..2c644f3db9c56bf3787c0f07a2dcd6a6430899fc 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
@@ -27,6 +27,7 @@ import org.springframework.dao.DataIntegrityViolationException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.business.IEntityOperationChecker;
 import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.util.RelationshipUtils;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.util.SampleUtils;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IAttachmentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
@@ -353,9 +354,11 @@ public final class SampleBO extends AbstractSampleBusinessObject implements ISam
     {
         assert sample != null : "no sample has been loaded";
         assertInstanceSampleUpdateAllowed(Collections.singletonList(sample));
-        sampleAttachment.setRegistrator(findPerson());
+        PersonPE user = findPerson();
+        sampleAttachment.setRegistrator(user);
         escapeFileName(sampleAttachment);
         attachments.add(sampleAttachment);
+        RelationshipUtils.updateModificationDateAndModifier(sample, user);
     }
 
     private void escapeFileName(final AttachmentPE attachment)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/builders/SampleUpdatesDTOBuilder.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/builders/SampleUpdatesDTOBuilder.java
index 1ad9cf6467e9cc2910330c59a8271f54d80d9e21..74a8bea63441f9f616d9c8532a26fd9a49637dc7 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/builders/SampleUpdatesDTOBuilder.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/builders/SampleUpdatesDTOBuilder.java
@@ -52,6 +52,8 @@ public class SampleUpdatesDTOBuilder
 
     private List<String> parentCodes = new ArrayList<String>();
 
+    private List<String> metaprojects = new ArrayList<String>();
+
     public SampleUpdatesDTOBuilder(Sample sample)
     {
         this(sample.getId());
@@ -94,12 +96,25 @@ public class SampleUpdatesDTOBuilder
         return this;
     }
 
+    public SampleUpdatesDTOBuilder metaProject(String metaProjectCode)
+    {
+        metaprojects.add(metaProjectCode);
+        return this;
+    }
+
+    public SampleUpdatesDTOBuilder attachment(NewAttachment attachment)
+    {
+        attachments.add(attachment);
+        return this;
+    }
+
     public SampleUpdatesDTO get()
     {
         SampleUpdatesDTO sampleUpdate =
                 new SampleUpdatesDTO(sampleId, properties, experimentIdentifierOrNull, attachments,
                         version, sampleIdentifier, containerIdentifierOrNull,
                         parentCodes.toArray(new String[0]));
+        sampleUpdate.setMetaprojectsOrNull(metaprojects.toArray(new String[0]));
         return sampleUpdate;
     }
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
index a781f37df5dc41f03073272087cc4ec4028cf290..99498202aa565ffe45fe01ae384ad5300fd6d3fb 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
@@ -20,6 +20,7 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.fail;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.testng.annotations.Test;
@@ -27,10 +28,12 @@ import org.testng.annotations.Test;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
@@ -198,6 +201,34 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
                 toolBox.renderMetaProjects(loadedExperiment.getMetaprojects()));
     }
 
+    @Test
+    public void testAddAttachment()
+    {
+        Experiment experiment = toolBox.createAndLoadExperiment(1);
+        ExperimentUpdatesDTO updates = new ExperimentUpdatesDTO();
+        updates.setVersion(experiment.getVersion());
+        updates.setExperimentId(new TechId(experiment));
+        updates.setProjectIdentifier(toolBox.createProjectIdentifier(experiment.getProject()
+                .getIdentifier()));
+        NewAttachment attachment = new NewAttachment();
+        attachment.setFilePath("greetings.txt");
+        attachment.setTitle("greetings");
+        attachment.setContent("hello world".getBytes());
+        updates.setAttachments(Arrays.asList(attachment));
+        updates.setProperties(experiment.getProperties());
+        String sessionToken = logIntoCommonClientService().getSessionID();
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+
+        genericServer.updateExperiment(sessionToken, updates);
+
+        Experiment loadedExperiment = toolBox.loadExperiment(experiment);
+        toolBox.checkModifierAndModificationDateOfBean(timeIntervalChecker, loadedExperiment,
+                "test");
+        List<Attachment> attachments = loadedExperiment.getAttachments();
+        assertEquals("greetings.txt", attachments.get(0).getFileName());
+        assertEquals(1, attachments.size());
+    }
+
     @Test
     public void testMoveSampleBetweenExperiments()
     {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/SampleOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/SampleOptimisticLockingTest.java
index c73fe6e44e0bb8adddddaf0a88ddab62566b731e..aa655e11e754170dc195c27950c880fd6e2bdb9f 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/SampleOptimisticLockingTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/SampleOptimisticLockingTest.java
@@ -19,12 +19,16 @@ package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.fail;
 
+import java.util.List;
+
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.PropertyBuilder;
@@ -255,4 +259,46 @@ public class SampleOptimisticLockingTest extends OptimisticLockingTestCase
         toolBox.checkModifierAndModificationDateOfBean(timeIntervalChecker, loadedSample, "test");
         toolBox.checkModifierAndModificationDateOfBean(timeIntervalChecker, loadedContainer, "test");
     }
+
+    @Test
+    public void testAddMetaProject()
+    {
+        Sample sample = toolBox.createAndLoadSample(1, null);
+        SampleUpdatesDTOBuilder builder = new SampleUpdatesDTOBuilder(sample);
+        builder.metaProject("TEST_METAPROJECTS");
+        String sessionToken = logIntoCommonClientService().getSessionID();
+        assertEquals("", toolBox.renderMetaProjects(toolBox.loadSample(sessionToken, sample)
+                .getMetaprojects()));
+
+        genericServer.updateSample(sessionToken, builder.get());
+
+        Sample loadedSample = toolBox.loadSample(sessionToken, sample);
+        assertEquals(sample.getModifier(), loadedSample.getModifier());
+        assertEquals(sample.getModificationDate(), loadedSample.getModificationDate());
+        assertEquals("/test/TEST_METAPROJECTS",
+                toolBox.renderMetaProjects(loadedSample.getMetaprojects()));
+        assertEquals("", toolBox.renderMetaProjects(toolBox.loadSample(sample).getMetaprojects()));
+    }
+
+    @Test
+    public void testAddAttachment()
+    {
+        Sample sample = toolBox.createAndLoadSample(1, null);
+        SampleUpdatesDTOBuilder builder = new SampleUpdatesDTOBuilder(sample);
+        NewAttachment attachment = new NewAttachment();
+        attachment.setFilePath("greetings.txt");
+        attachment.setTitle("greetings");
+        attachment.setContent("hello world".getBytes());
+        builder.attachment(attachment);
+        String sessionToken = logIntoCommonClientService().getSessionID();
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+
+        genericServer.updateSample(sessionToken, builder.get());
+
+        Sample loadedSample = toolBox.loadSample(sample);
+        toolBox.checkModifierAndModificationDateOfBean(timeIntervalChecker, loadedSample, "test");
+        List<Attachment> attachments = loadedSample.getAttachments();
+        assertEquals("greetings.txt", attachments.get(0).getFileName());
+        assertEquals(1, attachments.size());
+    }
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java
index e1b547579acc9234b6ff222982cd145d21407a71..7b33e0e8a09c76962d5b6915fa038a080e670dc6 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java
@@ -351,7 +351,12 @@ public class ToolBox
 
     public Sample loadSample(IIdentifierHolder sample)
     {
-        return etlService.tryGetSampleWithExperiment(systemSessionToken,
+        return loadSample(systemSessionToken, sample);
+    }
+
+    public Sample loadSample(String sessionToken, IIdentifierHolder sample)
+    {
+        return etlService.tryGetSampleWithExperiment(sessionToken,
                 SampleIdentifierFactory.parse(sample.getIdentifier()));
     }