diff --git a/caosdb-proto b/caosdb-proto
index 75e826bd318c39e63d324f71e035f08355ffc51f..73d85fb20bb16902c0a89dda697eed17994712bc 160000
--- a/caosdb-proto
+++ b/caosdb-proto
@@ -1 +1 @@
-Subproject commit 75e826bd318c39e63d324f71e035f08355ffc51f
+Subproject commit 73d85fb20bb16902c0a89dda697eed17994712bc
diff --git a/pom.xml b/pom.xml
index 493e02490eea6cd32f95eb3bd356cf6507de6073..5a2e9f9d60a8083b99ee61f2cefed59bde473da9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.caosdb</groupId>
   <artifactId>caosdb-server</artifactId>
-  <version>0.5.0-GRPC0.0.18</version>
+  <version>0.5.0-GRPC0.0.19</version>
   <packaging>jar</packaging>
   <name>CaosDB Server</name>
   <scm>
diff --git a/src/main/java/org/caosdb/server/entity/wrapper/Property.java b/src/main/java/org/caosdb/server/entity/wrapper/Property.java
index b3ce45b56527e40382d3971a61b43f9bc054d21f..064e2bd31fd329477d712c723ecd6462e94d3933 100644
--- a/src/main/java/org/caosdb/server/entity/wrapper/Property.java
+++ b/src/main/java/org/caosdb/server/entity/wrapper/Property.java
@@ -50,6 +50,7 @@ public class Property extends EntityWrapper {
     super(new Entity());
   }
 
+  /** Return the Property Index, the index of a property with respect to a containing Entity. */
   public int getPIdx() {
     return this.pIdx;
   }
@@ -58,6 +59,7 @@ public class Property extends EntityWrapper {
   private EntityInterface domain = null;
   private boolean isName;
 
+  /** Set the Property Index. */
   public void setPIdx(final int i) {
     this.pIdx = i;
   }
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index d0c659679390fa0dbf2ff3f939b7062c38a63f90..7f5434df15bd3653462c702a6a500f699e28f69b 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -40,6 +40,7 @@ import org.caosdb.api.entity.v1alpha1.UpdateRequest;
 import org.caosdb.api.entity.v1alpha1.UpdateResponse;
 import org.caosdb.api.entity.v1alpha1.Version;
 import org.caosdb.datetime.DateTimeInterface;
+import org.caosdb.server.CaosDBException;
 import org.caosdb.server.datatype.AbstractCollectionDatatype;
 import org.caosdb.server.datatype.AbstractDatatype;
 import org.caosdb.server.datatype.BooleanDatatype;
@@ -427,7 +428,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
 
   private org.caosdb.api.entity.v1alpha1.ReferenceDataType.Builder convertReferenceDatatype(
       final ReferenceDatatype datatype) {
-    return ReferenceDataType.newBuilder().setName(datatype.toString());
+    return ReferenceDataType.newBuilder().setName(datatype.getName());
   }
 
   public Iterable<? extends org.caosdb.api.entity.v1alpha1.Property> convert(
@@ -469,6 +470,13 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     return Integer.parseInt(id);
   }
 
+  /**
+   * Handle read-only transactions.
+   *
+   * @param request
+   * @return
+   * @throws Exception
+   */
   public MultiTransactionResponse retrieve(final MultiTransactionRequest request) throws Exception {
     final MultiTransactionResponse.Builder builder = MultiTransactionResponse.newBuilder();
     final RetrieveContainer container =
@@ -477,6 +485,12 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     FileDownload file_download = null;
 
     for (final TransactionRequest sub_request : request.getRequestsList()) {
+      if (sub_request.getWrappedRequestsCase() != WrappedRequestsCase.RETRIEVE_REQUEST) {
+        throw new CaosDBException(
+            "Cannot process a "
+                + sub_request.getWrappedRequestsCase().name()
+                + " in a read-only request.");
+      }
       final boolean fileDownload = sub_request.getRetrieveRequest().getRegisterFileDownload();
       if (sub_request.getRetrieveRequest().hasQuery()
           && !sub_request.getRetrieveRequest().getQuery().getQuery().isBlank()) {
@@ -563,104 +577,205 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     return System.currentTimeMillis();
   }
 
+  /**
+   * Handle all entity transactions.
+   *
+   * @param request
+   * @return
+   * @throws Exception
+   */
   public MultiTransactionResponse transaction(final MultiTransactionRequest request)
       throws Exception {
-    // we currently can only process one request type per multi transaction request.
-    WrappedRequestsCase requestCase = WrappedRequestsCase.WRAPPEDREQUESTS_NOT_SET;
-
     if (request.getRequestsCount() > 0) {
-      requestCase = request.getRequests(0).getWrappedRequestsCase();
-    }
-
-    switch (requestCase) {
-      case RETRIEVE_REQUEST:
-        return retrieve(request);
-      case DELETE_REQUEST:
-        return delete(request);
-      default:
-        return MultiTransactionResponse.newBuilder()
-            .addResponses(singleTransaction(request.getRequests(0)))
-            .build();
-    }
-  }
-
-  public TransactionResponse singleTransaction(final TransactionRequest request) throws Exception {
-    final WrappedRequestsCase requestCase = request.getWrappedRequestsCase();
-    switch (requestCase) {
-      case INSERT_REQUEST:
-        return TransactionResponse.newBuilder()
-            .setInsertResponse(insert(request.getInsertRequest()))
-            .build();
-      case UPDATE_REQUEST:
-        return TransactionResponse.newBuilder()
-            .setUpdateResponse(update(request.getUpdateRequest()))
-            .build();
-      default:
-        throw new UnsupportedOperationException("Not implemented");
+      // we only test the first request and raise errors when subsequent sub-transactions do not
+      // fit.
+      final WrappedRequestsCase requestCase = request.getRequests(0).getWrappedRequestsCase();
+      switch (requestCase) {
+        case RETRIEVE_REQUEST:
+          // Handle read-only transactions.
+          return retrieve(request);
+        default:
+          // Handle mixed-writed transactions.
+          return write(request);
+      }
+    } else {
+      // empty request, empty response.
+      return MultiTransactionResponse.newBuilder().build();
     }
   }
 
-  private MultiTransactionResponse delete(final MultiTransactionRequest requests) throws Exception {
+  /**
+   * Handle mixed-write transactions.
+   *
+   * <p>The current implementation fails fast, without attempts to execute a single request, if
+   * there are requests with non-integer IDs. This will change in the near future, once string IDs
+   * are supported by the server.
+   *
+   * @param requests
+   * @return
+   * @throws Exception
+   */
+  private MultiTransactionResponse write(final MultiTransactionRequest requests) throws Exception {
     final MultiTransactionResponse.Builder builder = MultiTransactionResponse.newBuilder();
     final WritableContainer container =
         new WritableContainer(
             SecurityUtils.getSubject(), getTimestamp(), getSRID(), new HashMap<String, String>());
-    for (final TransactionRequest request : requests.getRequestsList()) {
-      final DeleteRequest deleteRequest = request.getDeleteRequest();
-      final String id = deleteRequest.getId();
-      try {
-        final DeleteEntity entity = new DeleteEntity(getId(id));
-        container.add(entity);
 
-      } catch (final NumberFormatException e) {
-        // ID wasn't an integer - we handle this below
+    // put entities into the transaction object
+    for (final TransactionRequest subRequest : requests.getRequestsList()) {
+      switch (subRequest.getWrappedRequestsCase()) {
+        case INSERT_REQUEST:
+          {
+            final InsertRequest insertRequest = subRequest.getInsertRequest();
+            final Entity insertEntity = insertRequest.getEntityRequest().getEntity();
+
+            final InsertEntity entity =
+                new InsertEntity(
+                    insertEntity.getName().isEmpty() ? null : insertEntity.getName(),
+                    convert(insertEntity.getRole()));
+            convert(insertEntity, entity);
+            addFileUpload(container, entity, insertRequest.getEntityRequest());
+            container.add(entity);
+          }
+          break;
+        case UPDATE_REQUEST:
+          final UpdateRequest updateRequest = subRequest.getUpdateRequest();
+          final Entity updateEntity = updateRequest.getEntityRequest().getEntity();
+
+          try {
+            final UpdateEntity entity =
+                new UpdateEntity(getId(updateEntity.getId()), convert(updateEntity.getRole()));
+            entity.setName(updateEntity.getName().isEmpty() ? null : updateEntity.getName());
+            convert(updateEntity, entity);
+            addFileUpload(container, entity, updateRequest.getEntityRequest());
+            container.add(entity);
+          } catch (final NumberFormatException e) {
+            // ID wasn't an integer
+            return failedWriteDueToStringId(requests);
+          }
+          break;
+        case DELETE_REQUEST:
+          final DeleteRequest deleteRequest = subRequest.getDeleteRequest();
+          try {
+            final DeleteEntity entity = new DeleteEntity(getId(deleteRequest.getId()));
+            container.add(entity);
+
+          } catch (final NumberFormatException e) {
+            // ID wasn't an integer
+            return failedWriteDueToStringId(requests);
+          }
+          break;
+        default:
+          throw new CaosDBException(
+              "Cannot process a "
+                  + subRequest.getWrappedRequestsCase().name()
+                  + " in a write request.");
       }
     }
 
+    // execute the transaction
     final WriteTransaction transaction = new WriteTransaction(container);
+    transaction.setNoIdIsError(false);
     transaction.execute();
 
+    // put inserted/updated/deleted entities back into the response
     for (final EntityInterface entity : container) {
-      final IdResponse.Builder idResponse =
-          IdResponse.newBuilder().setId(entity.getId().toString());
+      final IdResponse.Builder idResponse = IdResponse.newBuilder();
+      if (entity.getId() != null) {
+        idResponse.setId(entity.getId().toString());
+      }
       appendMessages(entity, idResponse);
 
-      builder
-          .addResponsesBuilder()
-          .setDeleteResponse(DeleteResponse.newBuilder().setIdResponse(idResponse));
+      if (entity instanceof InsertEntity) {
+        builder
+            .addResponsesBuilder()
+            .setInsertResponse(InsertResponse.newBuilder().setIdResponse(idResponse));
+      } else if (entity instanceof UpdateEntity) {
+        builder
+            .addResponsesBuilder()
+            .setUpdateResponse(UpdateResponse.newBuilder().setIdResponse(idResponse));
+      } else {
+        builder
+            .addResponsesBuilder()
+            .setDeleteResponse(DeleteResponse.newBuilder().setIdResponse(idResponse));
+      }
     }
+    return builder.build();
+  }
 
-    // Add those entities which have not been retrieved because the have a string id
-    for (final TransactionRequest sub_request : requests.getRequestsList()) {
-      final String id = sub_request.getRetrieveRequest().getId();
-      if (!id.isBlank()) {
-        try {
-          getId(id);
-        } catch (final NumberFormatException e) {
-          // ID wasn't an integer - the server doesn't support string id's yet, so that entity
-          // cannot exist.
-          final IdResponse.Builder idResponse = IdResponse.newBuilder().setId(id);
-          idResponse.addErrors(convert(ServerMessages.ENTITY_DOES_NOT_EXIST));
-          builder.addResponses(
-              TransactionResponse.newBuilder()
-                  .setDeleteResponse(DeleteResponse.newBuilder().setIdResponse(idResponse)));
-        }
+  /**
+   * Handle a request which contains string id (which cannot be converted to integer ids) and return
+   * a response which has the "ENTITY_DOES_NOT_EXIST" error for all entities with affected ids.
+   *
+   * <p>This does not attempt to execute a single request.
+   *
+   * @param request
+   * @return
+   */
+  private MultiTransactionResponse failedWriteDueToStringId(final MultiTransactionRequest request) {
+    final org.caosdb.api.entity.v1alpha1.MultiTransactionResponse.Builder builder =
+        MultiTransactionResponse.newBuilder();
+    for (final TransactionRequest subRequest : request.getRequestsList()) {
+      final IdResponse.Builder idResponse = IdResponse.newBuilder();
+      switch (subRequest.getWrappedRequestsCase()) {
+        case INSERT_REQUEST:
+          builder
+              .addResponsesBuilder()
+              .setInsertResponse(InsertResponse.newBuilder().setIdResponse(idResponse));
+
+          break;
+        case UPDATE_REQUEST:
+          final UpdateRequest updateRequest = subRequest.getUpdateRequest();
+          final Entity updateEntity = updateRequest.getEntityRequest().getEntity();
+
+          idResponse.setId(updateEntity.getId());
+          try {
+            getId(updateEntity.getId());
+          } catch (final NumberFormatException e) {
+            // ID wasn't an integer
+            idResponse.addErrors(convert(ServerMessages.ENTITY_DOES_NOT_EXIST));
+          }
+          builder
+              .addResponsesBuilder()
+              .setUpdateResponse(UpdateResponse.newBuilder().setIdResponse(idResponse));
+          break;
+        case DELETE_REQUEST:
+          final DeleteRequest deleteRequest = subRequest.getDeleteRequest();
+          idResponse.setId(deleteRequest.getId());
+          try {
+            getId(deleteRequest.getId());
+          } catch (final NumberFormatException e) {
+            // ID wasn't an integer
+            idResponse.addErrors(convert(ServerMessages.ENTITY_DOES_NOT_EXIST));
+          }
+          builder
+              .addResponsesBuilder()
+              .setDeleteResponse(DeleteResponse.newBuilder().setIdResponse(idResponse));
+          break;
+        default:
+          throw new CaosDBException(
+              "Cannot process a "
+                  + subRequest.getWrappedRequestsCase().name()
+                  + " in a write request.");
       }
     }
     return builder.build();
   }
 
-  private InsertResponse insert(final InsertRequest insertRequest) throws Exception {
-    final EntityRequest entityRequest = insertRequest.getEntityRequest();
-    final Entity insertEntity = entityRequest.getEntity();
-    final InsertEntity entity =
-        new InsertEntity(
-            insertEntity.getName().isEmpty() ? null : insertEntity.getName(),
-            convert(insertEntity.getRole()));
-
-    return InsertResponse.newBuilder()
-        .setIdResponse(write(convert(insertEntity, entity), entityRequest))
-        .build();
+  private void addFileUpload(
+      final WritableContainer container,
+      final EntityInterface entity,
+      final EntityRequest entityRequest) {
+    if (entityRequest.hasUploadId()) {
+      final FileProperties uploadFile =
+          fileTransmissionService.getUploadFile(entityRequest.getUploadId());
+      if (uploadFile == null) {
+        entity.addError(ServerMessages.FILE_HAS_NOT_BEEN_UPLOAED);
+      } else {
+        container.addFile(uploadFile.getTmpIdentifyer(), uploadFile);
+        entity.getFileProperties().setTmpIdentifyer(uploadFile.getTmpIdentifyer());
+      }
+    }
   }
 
   private Role convert(final EntityRole role) {
@@ -678,57 +793,6 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     }
   }
 
-  private UpdateResponse update(final UpdateRequest updateRequest) throws Exception {
-    final EntityRequest entityRequest = updateRequest.getEntityRequest();
-    final Entity updateEntity = entityRequest.getEntity();
-    final String id = updateEntity.getId();
-    try {
-      final UpdateEntity entity = new UpdateEntity(getId(id), convert(updateEntity.getRole()));
-      entity.setName(updateEntity.getName().isEmpty() ? null : updateEntity.getName());
-
-      return UpdateResponse.newBuilder()
-          .setIdResponse(write(convert(updateEntity, entity), entityRequest))
-          .build();
-    } catch (final NumberFormatException e) {
-      // ID wasn't an integer - the server doesn't support string id's yet, so that entity cannot
-      // exist.
-      return UpdateResponse.newBuilder()
-          .setIdResponse(
-              IdResponse.newBuilder()
-                  .setId(id)
-                  .addErrors(convert(ServerMessages.ENTITY_DOES_NOT_EXIST)))
-          .build();
-    }
-  }
-
-  private IdResponse write(final EntityInterface entity, final EntityRequest entityRequest)
-      throws Exception {
-
-    final org.caosdb.api.entity.v1alpha1.IdResponse.Builder builder = IdResponse.newBuilder();
-    final WritableContainer container =
-        new WritableContainer(
-            SecurityUtils.getSubject(), getTimestamp(), getSRID(), new HashMap<>());
-    container.add(entity);
-    if (entityRequest.hasUploadId()) {
-      final FileProperties uploadFile =
-          fileTransmissionService.getUploadFile(entityRequest.getUploadId());
-      if (uploadFile == null) {
-        entity.addError(ServerMessages.FILE_HAS_NOT_BEEN_UPLOAED);
-      } else {
-        container.addFile(uploadFile.getTmpIdentifyer(), uploadFile);
-        entity.getFileProperties().setTmpIdentifyer(uploadFile.getTmpIdentifyer());
-      }
-    }
-    final WriteTransaction transaction = new WriteTransaction(container);
-    transaction.execute();
-    if (entity.hasId()) {
-      builder.setId(Integer.toString(entity.getId()));
-    }
-    appendMessages(entity, builder);
-
-    return builder.build();
-  }
-
   private void appendMessages(
       final EntityInterface from,
       final org.caosdb.api.entity.v1alpha1.EntityResponse.Builder builder) {
@@ -774,6 +838,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
   }
 
   private EntityInterface convert(final Entity from, final EntityInterface entity) {
+    entity.setName(from.getName().isEmpty() ? null : from.getName());
     entity.setDescription(from.getDescription().isBlank() ? null : from.getDescription());
     if (!from.getUnit().isBlank()) {
       entity.addProperty(getUnit(from.getUnit()));
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
index e663874189ee0301a5b30452468391711624b606..fa1c6fd36771e0ddcd08b330724ef1d6aa725956 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
@@ -60,7 +60,7 @@ public class CheckParValid extends EntityJob {
             // The parent has neither an id nor a name.
             // Therefore it cannot be identified.
 
-            throw ServerMessages.ENTITY_HAS_NO_NAME_AND_NO_ID;
+            throw ServerMessages.ENTITY_HAS_NO_NAME_OR_ID;
           }
 
           if (parent.hasId()) {
@@ -139,8 +139,8 @@ public class CheckParValid extends EntityJob {
       if (par.getEntityStatus() != EntityStatus.IGNORE) {
         for (final Parent par2 : getEntity().getParents()) {
           if (par != par2 && par2.getEntityStatus() != EntityStatus.IGNORE) {
-            if ((par.hasId() && par2.hasId() && par.getId().equals(par2.getId()))
-                || (par.hasName() && par2.hasName() && par.getName().equals(par2.getName()))) {
+            if (par.hasId() && par2.hasId() && par.getId().equals(par2.getId())
+                || par.hasName() && par2.hasName() && par.getName().equals(par2.getName())) {
               if (!Objects.equal(par.getFlag("inheritance"), par2.getFlag("inheritance"))) {
                 getEntity().addError(ServerMessages.PARENT_DUPLICATES_ERROR);
                 getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
diff --git a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
index 62a9beea1921f34dd3646bcc78ed9086d05e6098..daaf78ec58de00553b0a15e040e5c5435265ec0c 100644
--- a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
@@ -24,6 +24,7 @@ package org.caosdb.server.transaction;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import org.apache.shiro.SecurityUtils;
@@ -67,10 +68,17 @@ import org.caosdb.server.utils.ServerMessages;
 public class WriteTransaction extends Transaction<WritableContainer>
     implements WriteTransactionInterface {
 
+  private boolean noIdIsError = true;
+
   public WriteTransaction(final WritableContainer container) {
     super(container);
   }
 
+  /** Set if it is an error, if an Entity has no ID but just a name upon update. */
+  public void setNoIdIsError(final boolean noIdIsError) {
+    this.noIdIsError = noIdIsError;
+  }
+
   @Override
   protected final void preTransaction() throws InterruptedException {
     // Acquire strong access. No other thread can have access until this strong access is released.
@@ -288,7 +296,7 @@ public class WriteTransaction extends Transaction<WritableContainer>
         entity.setEntityStatus(EntityStatus.UNQUALIFIED);
         entity.addError(ServerMessages.AUTHORIZATION_ERROR);
         entity.addInfo(exc.getMessage());
-      } catch (ClassCastException exc) {
+      } catch (final ClassCastException exc) {
         // not an update entity. ignore.
       }
 
@@ -308,10 +316,10 @@ public class WriteTransaction extends Transaction<WritableContainer>
 
       // split up the TransactionContainer into three containers, one for each
       // type of writing transaction.
-      TransactionContainer inserts = new TransactionContainer();
-      TransactionContainer updates = new TransactionContainer();
-      TransactionContainer deletes = new TransactionContainer();
-      for (EntityInterface entity : getContainer()) {
+      final TransactionContainer inserts = new TransactionContainer();
+      final TransactionContainer updates = new TransactionContainer();
+      final TransactionContainer deletes = new TransactionContainer();
+      for (final EntityInterface entity : getContainer()) {
         if (entity instanceof InsertEntity) {
           inserts.add(entity);
         } else if (entity instanceof UpdateEntity) {
@@ -354,7 +362,7 @@ public class WriteTransaction extends Transaction<WritableContainer>
    * @throws IOException
    * @throws NoSuchAlgorithmException
    */
-  public static HashSet<Permission> deriveUpdate(
+  public HashSet<Permission> deriveUpdate(
       final EntityInterface newEntity, final EntityInterface oldEntity)
       throws NoSuchAlgorithmException, IOException, CaosDBException {
     final HashSet<Permission> needPermissions = new HashSet<>();
@@ -461,46 +469,34 @@ public class WriteTransaction extends Transaction<WritableContainer>
     }
 
     // properties
-    outerLoop:
-    for (final EntityInterface newProperty : newEntity.getProperties()) {
-
-      // find corresponding oldProperty for this new property and make a
-      // diff.
-      if (newProperty.hasId()) {
-        for (final EntityInterface oldProperty : oldEntity.getProperties()) {
-          if (newProperty.getId().equals(oldProperty.getId())) {
-            // do not check again.
-            oldEntity.getProperties().remove(oldProperty);
-
-            if (((Property) oldProperty).getPIdx() != ((Property) newProperty).getPIdx()) {
-              // change order of properties
-              needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
-              needPermissions.add(EntityPermission.UPDATE_REMOVE_PROPERTY);
-              updatetable = true;
-            }
-
-            deriveUpdate(newProperty, oldProperty);
-            if (newProperty.getEntityStatus() == EntityStatus.QUALIFIED) {
-              needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
-              needPermissions.add(EntityPermission.UPDATE_REMOVE_PROPERTY);
-              updatetable = true;
-            }
+    for (final Property newProperty : newEntity.getProperties()) {
+
+      // find corresponding oldProperty for this new property and make a diff (existing property,
+      // same property index in this entity, equal content?).
+      final Property oldProperty = findOldEntity(newProperty, oldEntity.getProperties());
+      if (oldProperty != null) {
+        // do not check again.
+        oldEntity.getProperties().remove(oldProperty);
+
+        if (oldProperty.getPIdx() != newProperty.getPIdx()) {
+          // change order of properties
+          needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
+          needPermissions.add(EntityPermission.UPDATE_REMOVE_PROPERTY);
+          updatetable = true;
+        }
 
-            continue outerLoop;
-          }
+        deriveUpdate(newProperty, oldProperty);
+        if (newProperty.getEntityStatus() == EntityStatus.QUALIFIED) {
+          needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
+          needPermissions.add(EntityPermission.UPDATE_REMOVE_PROPERTY);
+          updatetable = true;
         }
+
       } else {
-        newProperty.setEntityStatus(EntityStatus.UNQUALIFIED);
-        newProperty.addError(ServerMessages.ENTITY_HAS_NO_ID);
-        newProperty.addInfo("On updates, allways specify the id not just the name.");
-        newEntity.addError(ServerMessages.ENTITY_HAS_UNQUALIFIED_PROPERTIES);
-        newEntity.setEntityStatus(EntityStatus.UNQUALIFIED);
-        return needPermissions;
+        // no corresponding property found -> this property is new.
+        needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
+        updatetable = true;
       }
-
-      // no corresponding property found -> this property is new.
-      needPermissions.add(EntityPermission.UPDATE_ADD_PROPERTY);
-      updatetable = true;
     }
 
     // some old properties left (and not matched with new ones) -> there are
@@ -511,30 +507,20 @@ public class WriteTransaction extends Transaction<WritableContainer>
     }
 
     // update parents
-    outerLoop:
     for (final Parent newParent : newEntity.getParents()) {
 
       // find corresponding oldParent
-      if (newParent.hasId()) {
-        for (final Parent oldParent : oldEntity.getParents()) {
-          if (oldParent.getId().equals(newParent.getId())) {
-            // still there! do not check this one again
-            oldEntity.getParents().remove(oldParent);
-            continue outerLoop;
-          }
-        }
+      final Parent oldProperty = findOldEntity(newParent, oldEntity.getParents());
+
+      if (oldProperty != null) {
+        // do not check again.
+        oldEntity.getParents().remove(oldProperty);
+
       } else {
-        newParent.setEntityStatus(EntityStatus.UNQUALIFIED);
-        newParent.addError(ServerMessages.ENTITY_HAS_NO_ID);
-        newParent.addInfo("On updates, allways specify the id not just the name.");
-        newEntity.addError(ServerMessages.ENTITY_HAS_UNQUALIFIED_PROPERTIES);
-        newEntity.setEntityStatus(EntityStatus.UNQUALIFIED);
-        return needPermissions;
+        // no corresponding parent found -> this parent is new.
+        needPermissions.add(EntityPermission.UPDATE_ADD_PARENT);
+        updatetable = true;
       }
-
-      // no corresponding parent found -> this parent is new.
-      needPermissions.add(EntityPermission.UPDATE_ADD_PARENT);
-      updatetable = true;
     }
 
     // some old parents left (and not matched with new ones) -> there are
@@ -553,6 +539,35 @@ public class WriteTransaction extends Transaction<WritableContainer>
     return needPermissions;
   }
 
+  /**
+   * Attempt to find a (sparse) entity among a list of entities.
+   *
+   * <p>If no match by ID can be found, matching by name is attempted next, but only if noIdIsError
+   * is false.
+   */
+  private <T extends EntityInterface> T findOldEntity(
+      final EntityInterface newEntity, final List<T> oldEntities) {
+    if (newEntity.hasId()) {
+      for (final T oldEntity : oldEntities) {
+        if (Objects.equals(oldEntity.getId(), newEntity.getId())) {
+          return oldEntity;
+        }
+      }
+    } else if (noIdIsError) {
+      newEntity.addError(ServerMessages.ENTITY_HAS_NO_ID);
+      newEntity.addInfo("On updates, always specify the id not just the name.");
+    } else if (newEntity.hasName()) {
+      for (final T oldEntity : oldEntities) {
+        if (oldEntity.getName().equals(newEntity.getName())) {
+          return oldEntity;
+        }
+      }
+    } else {
+      newEntity.addError(ServerMessages.ENTITY_HAS_NO_NAME_OR_ID);
+    }
+    return null;
+  }
+
   public String getSRID() {
     return getContainer().getRequestId();
   }
diff --git a/src/main/java/org/caosdb/server/utils/ServerMessages.java b/src/main/java/org/caosdb/server/utils/ServerMessages.java
index cbca0b2dca1d967536be596547f57c20a2e7593f..a12b9bc4b7c031f39a4aad99e131439440cde621 100644
--- a/src/main/java/org/caosdb/server/utils/ServerMessages.java
+++ b/src/main/java/org/caosdb/server/utils/ServerMessages.java
@@ -74,9 +74,6 @@ public class ServerMessages {
   public static final Message NAME_DUPLICATES =
       new Message(MessageType.Error, 0, "Entity can not be identified due to name duplicates.");
 
-  public static final Message ENTITY_HAS_NO_NAME_AND_NO_ID =
-      new Message(MessageType.Error, 0, "Entity has no name and no ID.");
-
   public static final Message ENTITY_HAS_NO_PROPERTIES =
       new Message(MessageType.Error, 0, "Entity has no properties.");
 
diff --git a/src/test/java/org/caosdb/server/transaction/UpdateTest.java b/src/test/java/org/caosdb/server/transaction/UpdateTest.java
index d22fbea8982b1f8d88c9ccdf069a0c8a816add25..fb121c260a7706e806ddc73e9005ea4a440f1510 100644
--- a/src/test/java/org/caosdb/server/transaction/UpdateTest.java
+++ b/src/test/java/org/caosdb/server/transaction/UpdateTest.java
@@ -29,22 +29,29 @@ import static org.junit.Assert.assertEquals;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import org.caosdb.server.CaosDBException;
+import org.caosdb.server.CaosDBServer;
 import org.caosdb.server.datatype.GenericValue;
 import org.caosdb.server.entity.Entity;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.StatementStatus;
 import org.caosdb.server.entity.wrapper.Property;
 import org.caosdb.server.utils.EntityStatus;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class UpdateTest {
 
+  @BeforeClass
+  public static void setup() throws IOException {
+    CaosDBServer.initServerProperties();
+  }
+
   @Test
   public void testDeriveUpdate_SameName()
       throws NoSuchAlgorithmException, IOException, CaosDBException {
     final Entity newEntity = new Entity("Name");
     final Entity oldEntity = new Entity("Name");
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newEntity.getEntityStatus(), EntityStatus.VALID);
   }
 
@@ -53,7 +60,7 @@ public class UpdateTest {
       throws NoSuchAlgorithmException, IOException, CaosDBException {
     final Entity newEntity = new Entity("NewName");
     final Entity oldEntity = new Entity("OldName");
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newEntity.getEntityStatus(), EntityStatus.QUALIFIED);
   }
 
@@ -67,7 +74,7 @@ public class UpdateTest {
     final Entity oldEntity = new Entity();
     oldEntity.addProperty(oldProperty);
 
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newEntity.getEntityStatus(), VALID);
   }
 
@@ -83,7 +90,7 @@ public class UpdateTest {
     final Entity oldEntity = new Entity();
     oldEntity.addProperty(oldProperty);
 
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newEntity.getEntityStatus(), QUALIFIED);
     assertEquals(newProperty.getEntityStatus(), VALID);
     assertEquals(newProperty2.getEntityStatus(), QUALIFIED);
@@ -124,7 +131,7 @@ public class UpdateTest {
 
     oldEntity.addProperty(oldProperty);
 
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newUnit.getEntityStatus(), VALID);
     assertEquals(newProperty.getEntityStatus(), VALID);
     assertEquals(newEntity.getEntityStatus(), VALID);
@@ -165,7 +172,7 @@ public class UpdateTest {
 
     oldEntity.addProperty(oldProperty);
 
-    WriteTransaction.deriveUpdate(newEntity, oldEntity);
+    new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
     assertEquals(newEntity.getEntityStatus(), QUALIFIED);
     assertEquals(newProperty.getEntityStatus(), QUALIFIED);
   }