diff --git a/CHANGELOG.md b/CHANGELOG.md
index be47de54cd33c917b8997eebaa55c31edfe71543..77982cc0837f905f10274f23f83bd53b6414bbb9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,9 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed ###
 
+* Inheritance of the unit is not working. (GRPC API)
+  [linkahead-server#264](https://gitlab.indiscale.com/caosdb/src/caosdb-server/-/issues/264)
+* Curly brackets in query lead to unexpected server error.
+  [linkahead-server#138](https://gitlab.com/linkahead/linkahead-server/-/issues/138)
 * Wrong url returned by FileSystem resource behind proxy.
 * `NullPointerException` in GRPC API converters when executing SELECT query on
   NULL values.
+* Fix parsing of decimal numbers. Fixes https://gitlab.com/linkahead/linkahead-server/-/issues/239
 
 ## [0.10.0] - 2023-06-02 ##
 (Florian Spreckelsen)
diff --git a/README_SETUP.md b/README_SETUP.md
index acb3a79ad256fbba6a0d0a69887bb7c7ba7b28b9..e3b6e3bc3e8a69c2ff1e162476819ec76b93dbe9 100644
--- a/README_SETUP.md
+++ b/README_SETUP.md
@@ -163,6 +163,9 @@ sources (if you called `make run` previously).
 
 `$ make test`
 
+You can run single unit test with
+`mvn test -X -Dtest=TestCQL#testDecimalNumber`
+
 
 ## Setup Eclipse
 
diff --git a/conf/core/jobs.csv b/conf/core/jobs.csv
index 84795bee8657288473188cd9e7a6af81f6295221..3da052ff8529770646669c2f997d830dcb57d649 100644
--- a/conf/core/jobs.csv
+++ b/conf/core/jobs.csv
@@ -1,8 +1,8 @@
 #
 # This file is a part of the CaosDB Project.
 #
-# Copyright (C) 2021 Timm Fitsche <t.fitschen@indiscale.com>
-# Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2021-2023 Timm Fitsche <t.fitschen@indiscale.com>
+# Copyright (C) 2021-2023 IndiScale GmbH <info@indiscale.com>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -22,6 +22,7 @@
 # DOMAIN_ID, ENTITY_ID, TRANSACTION, JOB, JOB_FAILURE_SEVERITY
 
 # general rules
+0,0,INSERT,GenerateEntityId,ERROR
 0,0,INSERT,CheckPropValid,ERROR
 0,0,INSERT,CheckParValid,ERROR
 0,0,INSERT,CheckParOblPropPresent,ERROR
@@ -30,8 +31,7 @@
 0,0,UPDATE,CheckParValid,ERROR
 0,0,UPDATE,CheckParOblPropPresent,ERROR
 0,0,UPDATE,CheckValueParsable,ERROR
-0,0,DELETE,CheckReferenceDependencyExistent,ERROR
-0,0,DELETE,CheckChildDependencyExistent,ERROR
+0,0,DELETE,CheckDependenciesBeforeDeletion,ERROR
 
 
 # role specific rules
diff --git a/conf/core/server.conf b/conf/core/server.conf
index 5df6c40ca04a9c6f22d03f61c937ab5fbeab565f..1e22c5c7a3aad2d0aa53b098eb4666e25e591f31 100644
--- a/conf/core/server.conf
+++ b/conf/core/server.conf
@@ -69,7 +69,7 @@ MYSQL_USER_NAME=caosdb
 # Password for the user
 MYSQL_USER_PASSWORD=random1234
 # Schema of mysql procedures and tables which is required by this CaosDB instance
-MYSQL_SCHEMA_VERSION=v5.0
+MYSQL_SCHEMA_VERSION=v6.0.0-SNAPSHOT-EXTID
 
 
 # --------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 05d1aa4b7d8e01b5cd3794b6fabbd01ea81a24ac..4fb8f7ac8f12b06c77f93906f29a950a2c6e083d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -381,9 +381,9 @@
         </executions>
       </plugin>
       <plugin>
-        <groupId>com.coveo</groupId>
+        <groupId>com.spotify.fmt</groupId>
         <artifactId>fmt-maven-plugin</artifactId>
-        <version>2.5.1</version>
+        <version>2.21.1</version>
         <configuration>
           <skip>
             <!-- Set skip to `true` to prevent auto-formatting while coding. -->
diff --git a/src/main/java/org/caosdb/datetime/FragmentDateTime.java b/src/main/java/org/caosdb/datetime/FragmentDateTime.java
index 38c16a988a0103a121767b99078c0ca41c6263d5..78ef7199970ac3aa52a53cae96744cd90fb23c20 100644
--- a/src/main/java/org/caosdb/datetime/FragmentDateTime.java
+++ b/src/main/java/org/caosdb/datetime/FragmentDateTime.java
@@ -21,7 +21,9 @@
  * ** end header
  */
 
-/** @review Daniel Hornung 2022-03-04 */
+/**
+ * @review Daniel Hornung 2022-03-04
+ */
 package org.caosdb.datetime;
 
 import java.util.Objects;
diff --git a/src/main/java/org/caosdb/datetime/UTCDateTime.java b/src/main/java/org/caosdb/datetime/UTCDateTime.java
index 1dd86cc975d4b92066f2cf44fff51493ade5babe..a7719d5a3f30d862be0d7646796a4f2800149b06 100644
--- a/src/main/java/org/caosdb/datetime/UTCDateTime.java
+++ b/src/main/java/org/caosdb/datetime/UTCDateTime.java
@@ -21,7 +21,9 @@
  * ** end header
  */
 
-/** @review Daniel Hornung 2022-03-04 */
+/**
+ * @review Daniel Hornung 2022-03-04
+ */
 package org.caosdb.datetime;
 
 import java.util.ArrayList;
diff --git a/src/main/java/org/caosdb/server/CaosDBServer.java b/src/main/java/org/caosdb/server/CaosDBServer.java
index 2a115c5cfa06ed0e3db85847c27fb4c8424eadaf..8c75cf51e9a85685c19c3de271f56b519b81add7 100644
--- a/src/main/java/org/caosdb/server/CaosDBServer.java
+++ b/src/main/java/org/caosdb/server/CaosDBServer.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -129,6 +129,7 @@ public class CaosDBServer extends Application {
   private static boolean NO_TLS = false;
   public static final String REQUEST_TIME_LOGGER = "REQUEST_TIME_LOGGER";
   public static final String REQUEST_ERRORS_LOGGER = "REQUEST_ERRORS_LOGGER";
+  private static boolean USE_CACHE = true;
   private static Scheduler SCHEDULER;
 
   public static String getServerProperty(final String key) {
@@ -153,6 +154,7 @@ public class CaosDBServer extends Application {
       parseArguments(args);
       initScheduler();
       initServerProperties();
+      initCaching();
       initTimeZone();
       initOneTimeTokens();
       initShiro();
@@ -198,6 +200,11 @@ public class CaosDBServer extends Application {
     SERVER_PROPERTIES = ServerProperties.initServerProperties();
   }
 
+  public static void initCaching() {
+    USE_CACHE =
+        !Boolean.parseBoolean(CaosDBServer.getServerProperty(ServerProperties.KEY_CACHE_DISABLE));
+  }
+
   /**
    * Precedence order:
    *
@@ -664,7 +671,7 @@ public class CaosDBServer extends Application {
               return 0;
             }
             return -1;
-          };
+          }
 
           @Override
           public int match(final String formattedString) {
@@ -886,6 +893,10 @@ public class CaosDBServer extends Application {
       throws SchedulerException {
     SCHEDULER.scheduleJob(job, trigger);
   }
+
+  public static boolean useCache() {
+    return USE_CACHE;
+  }
 }
 
 class CaosDBComponent extends Component {
diff --git a/src/main/java/org/caosdb/server/accessControl/Pam.java b/src/main/java/org/caosdb/server/accessControl/Pam.java
index 992665c1db3ef42d3770c71e89fa5444f43f9d95..76fde331dc97b51ed82083999e4d49b94176695d 100644
--- a/src/main/java/org/caosdb/server/accessControl/Pam.java
+++ b/src/main/java/org/caosdb/server/accessControl/Pam.java
@@ -145,7 +145,9 @@ public class Pam implements UserSource {
     return this.map;
   }
 
-  /** @see {@link UserSource#resolveRolesForUsername(String)} */
+  /**
+   * @see {@link UserSource#resolveRolesForUsername(String)}
+   */
   @Override
   public Set<String> resolveRolesForUsername(final String username) {
     final Set<String> resulting_roles = new HashSet<String>();
@@ -266,7 +268,9 @@ public class Pam implements UserSource {
     return username != null && isIncorporated(username);
   }
 
-  /** @see {@link UserSource#isValid(String, String)}. */
+  /**
+   * @see {@link UserSource#isValid(String, String)}.
+   */
   @Override
   public boolean isValid(final String username, final String password) {
     if (username != null && isIncorporated(username)) {
diff --git a/src/main/java/org/caosdb/server/caching/JCSCacheHelper.java b/src/main/java/org/caosdb/server/caching/JCSCacheHelper.java
index 1613b8be8194425ab14e5e68b9215a0ba92be8d3..f294e4bb029b7e03d2864ae832b3044685536404 100644
--- a/src/main/java/org/caosdb/server/caching/JCSCacheHelper.java
+++ b/src/main/java/org/caosdb/server/caching/JCSCacheHelper.java
@@ -62,8 +62,7 @@ public class JCSCacheHelper implements CacheHelper {
   }
 
   public static void init() {
-    final boolean disabled =
-        Boolean.parseBoolean(CaosDBServer.getServerProperty(ServerProperties.KEY_CACHE_DISABLE));
+    final boolean disabled = !CaosDBServer.useCache();
     init(CaosDBServer.getServerProperty(ServerProperties.KEY_CACHE_CONF_LOC), disabled);
   }
 
diff --git a/src/main/java/org/caosdb/server/database/BackendTransaction.java b/src/main/java/org/caosdb/server/database/BackendTransaction.java
index 05ea26c255ae5b2bd1e75df7f3fdc4d94fca5e5a..c014972ac52246e87a1d9e6f575a645125ab4c57 100644
--- a/src/main/java/org/caosdb/server/database/BackendTransaction.java
+++ b/src/main/java/org/caosdb/server/database/BackendTransaction.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -29,7 +29,6 @@ import org.caosdb.server.database.backend.implementation.MySQL.MySQLDeleteRole;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLDeleteSparseEntity;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLDeleteUser;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLGetAllNames;
-import org.caosdb.server.database.backend.implementation.MySQL.MySQLGetChildren;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLGetDependentEntities;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLGetFileRecordByPath;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLGetIDByName;
@@ -49,6 +48,7 @@ import org.caosdb.server.database.backend.implementation.MySQL.MySQLListUsers;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLLogUserVisit;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAll;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAllUncheckedFiles;
+import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveCurrentMaxId;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveDatatypes;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveEntityACL;
 import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveLogRecord;
@@ -86,7 +86,6 @@ import org.caosdb.server.database.backend.interfaces.FileCheckSize;
 import org.caosdb.server.database.backend.interfaces.FileExists;
 import org.caosdb.server.database.backend.interfaces.FileWasModifiedAfter;
 import org.caosdb.server.database.backend.interfaces.GetAllNamesImpl;
-import org.caosdb.server.database.backend.interfaces.GetChildrenImpl;
 import org.caosdb.server.database.backend.interfaces.GetDependentEntitiesImpl;
 import org.caosdb.server.database.backend.interfaces.GetFileIteratorImpl;
 import org.caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl;
@@ -107,6 +106,7 @@ import org.caosdb.server.database.backend.interfaces.ListUsersImpl;
 import org.caosdb.server.database.backend.interfaces.LogUserVisitImpl;
 import org.caosdb.server.database.backend.interfaces.RetrieveAllImpl;
 import org.caosdb.server.database.backend.interfaces.RetrieveAllUncheckedFilesImpl;
+import org.caosdb.server.database.backend.interfaces.RetrieveCurrentMaxIdImpl;
 import org.caosdb.server.database.backend.interfaces.RetrieveDatatypesImpl;
 import org.caosdb.server.database.backend.interfaces.RetrieveEntityACLImpl;
 import org.caosdb.server.database.backend.interfaces.RetrieveLogRecordImpl;
@@ -133,6 +133,18 @@ import org.caosdb.server.database.misc.TransactionBenchmark;
 import org.caosdb.server.utils.UndoHandler;
 import org.caosdb.server.utils.Undoable;
 
+/**
+ * Abstract class for backend transactions.
+ *
+ * <p>This class is the glue between the Transaction layer and the actual implementation of the
+ * communication with the back end.
+ *
+ * <p>This class also acts as a registry which stores which implementation is being used for which
+ * backend transaction interface.
+ *
+ * @see {@link Transaction}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public abstract class BackendTransaction implements Undoable {
 
   private final UndoHandler undoHandler = new UndoHandler();
@@ -153,7 +165,7 @@ public abstract class BackendTransaction implements Undoable {
   }
 
   /**
-   * Intialiaze the adapters to the database backend.
+   * Initialize the adapters to the database backend.
    *
    * <p>Currently this is hard-coded to the MySQL-Backend but the architecture of this class is
    * designed to make it easy in the future to choose other implementations (i.e. other back-ends)
@@ -163,7 +175,6 @@ public abstract class BackendTransaction implements Undoable {
       setImpl(GetAllNamesImpl.class, MySQLGetAllNames.class);
       setImpl(DeleteEntityPropertiesImpl.class, MySQLDeleteEntityProperties.class);
       setImpl(DeleteSparseEntityImpl.class, MySQLDeleteSparseEntity.class);
-      setImpl(GetChildrenImpl.class, MySQLGetChildren.class);
       setImpl(GetDependentEntitiesImpl.class, MySQLGetDependentEntities.class);
       setImpl(GetIDByNameImpl.class, MySQLGetIDByName.class);
       setImpl(GetInfoImpl.class, MySQLGetInfo.class);
@@ -213,6 +224,7 @@ public abstract class BackendTransaction implements Undoable {
       setImpl(ListUsersImpl.class, MySQLListUsers.class);
       setImpl(LogUserVisitImpl.class, MySQLLogUserVisit.class);
       setImpl(RetrieveEntityACLImpl.class, MySQLRetrieveEntityACL.class);
+      setImpl(RetrieveCurrentMaxIdImpl.class, MySQLRetrieveCurrentMaxId.class);
     }
   }
 
diff --git a/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java b/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java
index f12c78e31bf28799b8c8ead1c9ff311a65bb01ef..478953cbbcd25693dca3df92a3ede6371b4f2212 100644
--- a/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java
+++ b/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java
@@ -60,6 +60,7 @@ class ReadAccessSemaphore extends Semaphore implements Releasable {
   private AtomicInteger acquired = new AtomicInteger(0); // how many threads have read access
   Semaphore writersBlock =
       new Semaphore(1, true); // This semaphore is blocked as long as there are any
+
   // unreleased read permits.
 
   public ReadAccessSemaphore() {
diff --git a/src/main/java/org/caosdb/server/database/access/AbstractAccess.java b/src/main/java/org/caosdb/server/database/access/AbstractAccess.java
index 1d30bd3fee7187b9c44378e5b94c1c6d97287f00..574dabedd0db28ded611411ed8848f00be56a293 100644
--- a/src/main/java/org/caosdb/server/database/access/AbstractAccess.java
+++ b/src/main/java/org/caosdb/server/database/access/AbstractAccess.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.access;
 
@@ -26,11 +25,18 @@ import java.util.HashMap;
 import org.caosdb.server.database.misc.DBHelper;
 import org.caosdb.server.database.misc.RollBackHandler;
 import org.caosdb.server.transaction.TransactionInterface;
+import org.caosdb.server.utils.UseCacheResourceDelegate;
 
-public abstract class AbstractAccess<T extends TransactionInterface> implements Access {
+/**
+ * Abstract implementation of an Access.
+ *
+ * @see {@link Access}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public abstract class AbstractAccess<T extends TransactionInterface>
+    extends UseCacheResourceDelegate implements Access {
 
   private HashMap<String, DBHelper> helpers = new HashMap<String, DBHelper>();
-  private Boolean useCache = true;
   private final T transaction;
   private boolean released = false;
 
@@ -73,22 +79,6 @@ public abstract class AbstractAccess<T extends TransactionInterface> implements
     }
   }
 
-  @Override
-  public void setUseCache(final Boolean useCache) {
-    this.useCache = useCache;
-  }
-  /**
-   * Whether the transaction allows to use the query cache or other caches. This is controlled by
-   * the "cache" flag.
-   *
-   * @see {@link NoCache}
-   * @return true if caching is encouraged.
-   */
-  @Override
-  public boolean useCache() {
-    return this.useCache;
-  }
-
   @Override
   public void commit() throws Exception {
     synchronized (this.helpers) {
diff --git a/src/main/java/org/caosdb/server/database/access/Access.java b/src/main/java/org/caosdb/server/database/access/Access.java
index 228e8e004aea7454a287bccd898794c2bb4f1b9c..6b8a521cffd5f0d817f9a9b0a4ecce357fb82d76 100644
--- a/src/main/java/org/caosdb/server/database/access/Access.java
+++ b/src/main/java/org/caosdb/server/database/access/Access.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,14 +18,29 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.access;
 
 import org.caosdb.server.database.misc.DBHelper;
+import org.caosdb.server.utils.UseCacheResource;
 
-public interface Access {
+/**
+ * Access Interface.
+ *
+ * <p>The access object is part of a Transactions state and it is the glue between the Transaction
+ * and the actual backend implementation of those transactions. It represents different levels of
+ * access (RO, RW) and provides all the helper objects shared by all the single calls to the backend
+ * (package .../database/backend/implementation/...).
+ *
+ * <p>It is further used to commit or roll-back the owning transaction.
+ *
+ * <p>The DatabaseAccessManager issues the Access to a requesting Transaction.
+ *
+ * @see {@link Transaction}
+ * @see {@link DatabaseAccessManager}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public interface Access extends UseCacheResource {
 
   public abstract void setHelper(String name, DBHelper helper);
 
@@ -33,8 +49,4 @@ public interface Access {
   public abstract void release();
 
   public abstract void commit() throws Exception;
-
-  public abstract void setUseCache(Boolean useCache);
-
-  public boolean useCache();
 }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseConnectionPool.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseConnectionPool.java
index 997de3141db6fd49ac510fa61150a2d16e7d5416..8234d948eb3af1dd490e6ef1062de98504e3575d 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseConnectionPool.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseConnectionPool.java
@@ -23,7 +23,6 @@
 package org.caosdb.server.database.backend.implementation.MySQL;
 
 import com.google.common.base.Objects;
-import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -75,8 +74,12 @@ class DatabaseConnectionPool {
   private static ConnectionPool instance = null;
 
   private static synchronized ConnectionPool createConnectionPool()
-      throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException,
-          ConnectionException, CaosDBException {
+      throws ClassNotFoundException,
+          InstantiationException,
+          IllegalAccessException,
+          SQLException,
+          ConnectionException,
+          CaosDBException {
 
     final String url =
         "jdbc:mysql://"
@@ -244,20 +247,6 @@ class DatabaseConnectionPool {
         System.exit(1);
       }
 
-      // set auto_increment on table entities to the maximum entity_id of
-      // table transaction_log;
-      // Why? MYSQL seems to reset the
-      // auto_increment value each time the MySQL server is being
-      // restarted to the maximum of ids in the entities table. But if
-      // some of the ids had been used yet, we don't want to use them
-      // again.
-      final CallableStatement prepareCall = con.prepareCall("call initAutoIncrement()");
-      try {
-        prepareCall.execute();
-      } catch (final SQLException e) {
-        logger.error("Could inititialize the autoincrement value for the entities table.", e);
-        System.exit(1);
-      }
     } finally {
       con.close();
     }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java
index f7d364ae6376524ef892de3353d699547417717e..6528627d0e7080452827f8b70b87c34c78ac6c57 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/DatabaseUtils.java
@@ -152,9 +152,10 @@ public class DatabaseUtils {
   public static void parseOverrides(final List<ProtoProperty> properties, final ResultSet rs)
       throws SQLException {
     while (rs.next()) {
-      final int property_id = rs.getInt("property_id");
+      String property_id = rs.getString("property_id");
+      if (rs.wasNull()) property_id = rs.getString("InternalPropertyID");
       for (final FlatProperty p : properties) {
-        if (p.id == property_id) {
+        if (p.id.equals(property_id)) {
           final String name = bytes2UTF8(rs.getBytes("name_override"));
           if (name != null) {
             p.name = name;
@@ -180,7 +181,10 @@ public class DatabaseUtils {
     final List<ProtoProperty> ret = new LinkedList<>();
     while (rs.next()) {
       ProtoProperty pp = new ProtoProperty();
-      pp.id = rs.getInt("PropertyID");
+      pp.id = rs.getString("PropertyID");
+      if (rs.wasNull()) {
+        pp.id = rs.getString("InternalPropertyID");
+      }
       pp.value = bytes2UTF8(rs.getBytes("PropertyValue"));
       pp.status = bytes2UTF8(rs.getBytes("PropertyStatus"));
       pp.idx = rs.getInt("PropertyIndex");
@@ -215,7 +219,7 @@ public class DatabaseUtils {
    */
   public static SparseEntity parseEntityResultSet(final ResultSet rs) throws SQLException {
     final SparseEntity ret = parseNameRoleACL(rs);
-    ret.id = rs.getInt("EntityID");
+    ret.id = rs.getString("EntityID");
     ret.description = bytes2UTF8(rs.getBytes("EntityDesc"));
     ret.datatype = bytes2UTF8(rs.getBytes("Datatype"));
     ret.collection = bytes2UTF8(rs.getBytes("Collection"));
@@ -233,7 +237,7 @@ public class DatabaseUtils {
     final LinkedList<VerySparseEntity> ret = new LinkedList<>();
     while (rs.next()) {
       final VerySparseEntity vsp = new VerySparseEntity();
-      vsp.id = rs.getInt("ParentID");
+      vsp.id = rs.getString("ParentID");
       vsp.name = bytes2UTF8(rs.getBytes("ParentName"));
       vsp.description = bytes2UTF8(rs.getBytes("ParentDescription"));
       vsp.role = bytes2UTF8(rs.getBytes("ParentRole"));
@@ -247,7 +251,7 @@ public class DatabaseUtils {
       EntityInterface entity, List<ProtoProperty> protos) {
     final ArrayList<Property> ret = new ArrayList<Property>();
     for (final ProtoProperty pp : protos) {
-      if (pp.id.equals(entity.getId().toInteger())) {
+      if (pp.id.equals(entity.getId().toString())) {
         if (pp.value != null) {
           entity.setValue(new GenericValue(pp.value));
         }
@@ -328,8 +332,7 @@ public class DatabaseUtils {
               return ((Entry<Integer, String>) x).getKey() - ((Entry<Integer, String>) y).getKey();
             });
         pp.collValues =
-            pp.collValues
-                .stream()
+            pp.collValues.stream()
                 .map((x) -> (Object) ((Entry<Integer, String>) x).getValue())
                 .collect(Collectors.toList());
       }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteEntityProperties.java
index f8cba7d4c9734c1e6e12b72498ceaa6c57ed1a17..747cf50d8390d943fce5ffbf596debe5659b8df9 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteEntityProperties.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteEntityProperties.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -44,7 +43,7 @@ public class MySQLDeleteEntityProperties extends MySQLTransaction
     try {
       final PreparedStatement stmt = prepareStatement(STMT_DELETE_ENTITY_PROPERTIES);
 
-      stmt.setInt(1, id.toInteger());
+      stmt.setString(1, id.toString());
       stmt.execute();
     } catch (final SQLIntegrityConstraintViolationException exc) {
       throw new IntegrityException(exc);
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteSparseEntity.java
index 7fe8ac303b53ec26dc947c1e4a84e648d7b6517d..a1ab389b6878c06c5fd965d0952d422f11134c0e 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteSparseEntity.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLDeleteSparseEntity.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -44,7 +43,7 @@ public class MySQLDeleteSparseEntity extends MySQLTransaction implements DeleteS
     try {
       final PreparedStatement stmt = prepareStatement(STMT_DELETE_SPARSE_ENTITY);
 
-      stmt.setInt(1, id.toInteger());
+      stmt.setString(1, id.toString());
       stmt.execute();
     } catch (final SQLIntegrityConstraintViolationException exc) {
       throw new IntegrityException(exc);
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetChildren.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetChildren.java
deleted file mode 100644
index 3c1cebf1e20a720a5f726e378bb22b1ad61c850a..0000000000000000000000000000000000000000
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetChildren.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-package org.caosdb.server.database.backend.implementation.MySQL;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.util.LinkedList;
-import java.util.List;
-import org.caosdb.server.database.access.Access;
-import org.caosdb.server.database.backend.interfaces.GetChildrenImpl;
-import org.caosdb.server.database.exceptions.TransactionException;
-import org.caosdb.server.entity.EntityID;
-
-public class MySQLGetChildren extends MySQLTransaction implements GetChildrenImpl {
-
-  public MySQLGetChildren(final Access access) {
-    super(access);
-  }
-
-  public static final String STMT_GET_CHILDREN =
-      "Select child from isa_cache where parent=? and rpath=child";
-
-  @Override
-  public List<EntityID> execute(final EntityID entity) throws TransactionException {
-    try {
-      final PreparedStatement stmt = prepareStatement(STMT_GET_CHILDREN);
-
-      stmt.setInt(1, entity.toInteger());
-
-      ResultSet rs = null;
-      try {
-        rs = stmt.executeQuery();
-        final List<EntityID> ret = new LinkedList<>();
-        while (rs.next()) {
-          ret.add(new EntityID(rs.getInt(1)));
-        }
-        return ret;
-      } finally {
-        if (rs != null && !rs.isClosed()) {
-          rs.close();
-        }
-      }
-    } catch (final Exception e) {
-      throw new TransactionException(e);
-    }
-  }
-}
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetDependentEntities.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetDependentEntities.java
index 9384c8a04861a01f1e56236b0ab42433d87990f5..2af80f802ca19eca806856bb653788b50ae5ecf9 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetDependentEntities.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetDependentEntities.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -31,6 +30,15 @@ import org.caosdb.server.database.backend.interfaces.GetDependentEntitiesImpl;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.entity.EntityID;
 
+/**
+ * Get a list of ids of all entities which require the given entity to exists.
+ *
+ * <p>That is the list of all direct child entities (by is-a relation), referenced entities (i.e.
+ * the given entity is a property's value), all properties which have this entity as their data type
+ * and all implemented properties which use this entity as their abtract property.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLGetDependentEntities extends MySQLTransaction
     implements GetDependentEntitiesImpl {
 
@@ -45,13 +53,13 @@ public class MySQLGetDependentEntities extends MySQLTransaction
     try {
       final PreparedStatement stmt = prepareStatement(STMT_GET_DEPENDENT_ENTITIES);
 
-      stmt.setInt(1, entity.toInteger());
+      stmt.setString(1, entity.toString());
 
       final ResultSet rs = stmt.executeQuery();
       try {
         final List<EntityID> ret = new LinkedList<>();
         while (rs.next()) {
-          ret.add(new EntityID(rs.getInt(1)));
+          ret.add(new EntityID(rs.getString(1)));
         }
         return ret;
       } finally {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetFileRecordByPath.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetFileRecordByPath.java
index 9b147d289b337f63dd359ce604719d9e00a149be..0dd10ec1bcdc97a095da661cb6cb2e2209da0955 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetFileRecordByPath.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetFileRecordByPath.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -30,6 +29,11 @@ import org.caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.database.proto.SparseEntity;
 
+/**
+ * Retrieve the entity id of a file with the given path (or null).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLGetFileRecordByPath extends MySQLTransaction implements GetFileRecordByPathImpl {
 
   public MySQLGetFileRecordByPath(final Access access) {
@@ -37,7 +41,7 @@ public class MySQLGetFileRecordByPath extends MySQLTransaction implements GetFil
   }
 
   public static final String STMT_GET_ID_BY_PATH =
-      "SELECT file_id, size, hex(hash) AS file_hash, checked_timestamp FROM files WHERE path=?";
+      "SELECT (Select id from entity_ids WHERE internal_id = files.file_id) as entity_id, size, hex(hash) AS file_hash, checked_timestamp FROM files WHERE path=?";
 
   @Override
   public SparseEntity execute(final String path) throws TransactionException {
@@ -49,7 +53,7 @@ public class MySQLGetFileRecordByPath extends MySQLTransaction implements GetFil
       try {
         if (rs.next()) {
           final SparseEntity ret = new SparseEntity();
-          ret.id = rs.getInt("file_id");
+          ret.id = rs.getString("entity_id");
           ret.fileHash = rs.getString("file_hash");
           ret.fileSize = rs.getLong("size");
           ret.fileChecked = rs.getLong("checked_timestamp");
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetIDByName.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetIDByName.java
index c2e28cd39929f71e874fb4a69c38261ed290b18a..5d3e3a7d707c0d7d451d0229426a959fc827e8ef 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetIDByName.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetIDByName.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,13 +18,12 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.sql.Types;
 import java.util.LinkedList;
 import java.util.List;
 import org.caosdb.server.database.access.Access;
@@ -31,6 +31,11 @@ import org.caosdb.server.database.backend.interfaces.GetIDByNameImpl;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.entity.EntityID;
 
+/**
+ * Retrieve the entity id of an entity with the given name (or null).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLGetIDByName extends MySQLTransaction implements GetIDByNameImpl {
 
   public MySQLGetIDByName(final Access access) {
@@ -42,34 +47,29 @@ public class MySQLGetIDByName extends MySQLTransaction implements GetIDByNameImp
    * Therefore {@link #STMT_AND_ROLE}, {@link #STMT_NOT_ROLE}, and {@link #STMT_LIMIT} can as
    * additional conditions.
    */
-  public static final String STMT_GET_ID_BY_NAME =
-      "Select n.entity_id AS id "
-          + "FROM name_data AS n JOIN entities AS e "
-          + "ON (n.domain_id=0 AND n.property_id=20 AND e.id = n.entity_id)"
-          + "WHERE n.value=?";
-
-  public static final String STMT_AND_ROLE = " AND e.role=?";
-  public static final String STMT_NOT_ROLE = " AND e.role!='ROLE'";
-  public static final String STMT_LIMIT = " LIMIT ";
+  public static final String STMT_GET_ID_BY_NAME = "call getIdByName(?, ?, ?)";
 
   @Override
   public List<EntityID> execute(final String name, final String role, final String limit)
       throws TransactionException {
     try {
-      final String stmtStr =
-          STMT_GET_ID_BY_NAME
-              + (role != null ? STMT_AND_ROLE : STMT_NOT_ROLE)
-              + (limit != null ? STMT_LIMIT + limit : "");
-      final PreparedStatement stmt = prepareStatement(stmtStr);
+      final PreparedStatement stmt = prepareStatement(STMT_GET_ID_BY_NAME);
 
       stmt.setString(1, name);
       if (role != null) {
         stmt.setString(2, role);
+      } else {
+        stmt.setNull(2, Types.VARCHAR);
+      }
+      if (limit != null) {
+        stmt.setString(3, limit);
+      } else {
+        stmt.setNull(3, Types.VARCHAR);
       }
       try (ResultSet rs = stmt.executeQuery()) {
         final List<EntityID> ret = new LinkedList<>();
         while (rs.next()) {
-          ret.add(new EntityID(rs.getInt("id")));
+          ret.add(new EntityID(rs.getString("id")));
         }
 
         return ret;
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetUpdateableChecksums.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetUpdateableChecksums.java
index 28c55032e0ae6b6c2fcfb779339a72b96c703ba0..81c0dfd6d489a104183e052aba6156372a96f8e9 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetUpdateableChecksums.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLGetUpdateableChecksums.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -30,11 +29,17 @@ import org.caosdb.server.database.backend.interfaces.GetUpdateableChecksumsImpl;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.entity.EntityID;
 
+/**
+ * Retrieve the entity ids of all files which have a checksum which should be updated (because the
+ * checksum is NULL, currently).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLGetUpdateableChecksums extends MySQLTransaction
     implements GetUpdateableChecksumsImpl {
 
   private final String GET_UPDATEABLE_CHECKSUMS =
-      "SELECT file_id FROM files WHERE hash IS NULL LIMIT 1";
+      "SELECT (SELECT id FROM entity_ids WHERE internal_id = files.file_id) AS entity_id FROM files WHERE hash IS NULL LIMIT 1";
 
   public MySQLGetUpdateableChecksums(final Access access) {
     super(access);
@@ -46,7 +51,7 @@ public class MySQLGetUpdateableChecksums extends MySQLTransaction
       final PreparedStatement stmt = prepareStatement(this.GET_UPDATEABLE_CHECKSUMS);
       final ResultSet rs = stmt.executeQuery();
       if (rs.next()) {
-        return new EntityID(rs.getInt(1));
+        return new EntityID(rs.getString(1));
       } else {
         return null;
       }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java
index c4cb7cf98e5da51f98d71b4c5f6fc91e6961892e..4260ae03e76eec7fab1e33957a00dedc2ef77e17 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
 import java.sql.PreparedStatement;
@@ -8,6 +27,15 @@ import org.caosdb.server.database.exceptions.IntegrityException;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.database.proto.SparseEntity;
 
+/**
+ * Insert an entity's (meaning: an abstract property's) data type.
+ *
+ * <p>This inserts the abstract property's data type as opposed to the (overridden data type which
+ * is being inserted/updated via InsertEntityPropertiesImpl.
+ *
+ * @see {@link InsertEntityPropertiesImpl}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLInsertEntityDatatype extends MySQLTransaction
     implements InsertEntityDatatypeImpl {
 
@@ -19,18 +47,13 @@ public class MySQLInsertEntityDatatype extends MySQLTransaction
    * Inserts atomic data types of properties into the data_type table. Has two parameters, the
    * property_id and the data type name.
    */
-  public static final String STMT_INSERT_ENTITY_DATATYPE =
-      "INSERT INTO data_type (domain_id, entity_id, property_id, datatype) "
-          + "SELECT 0, 0, ?, "
-          + "( SELECT entity_id FROM name_data WHERE domain_id = 0 AND property_id = 20 AND value = ? LIMIT 1);";
+  public static final String STMT_INSERT_ENTITY_DATATYPE = "call insertEntityDataType(?, ?)";
 
   /**
    * Inserts collection data types of properties into the data_type table. Has two parameters, the
    * property_id and the type of collection (e.g. 'LIST').
    */
-  public static final String STMT_INSERT_ENTITY_COLLECTION =
-      "INSERT INTO collection_type (domain_id, entity_id, property_id, collection) "
-          + "SELECT 0, 0, ?, ?;";
+  public static final String STMT_INSERT_ENTITY_COLLECTION = "call insertEntityCollection(?, ?)";
 
   @Override
   public void execute(final SparseEntity entity) {
@@ -38,7 +61,7 @@ public class MySQLInsertEntityDatatype extends MySQLTransaction
       final PreparedStatement insertEntityDatatypeStmt =
           prepareStatement(STMT_INSERT_ENTITY_DATATYPE);
 
-      insertEntityDatatypeStmt.setInt(1, entity.id);
+      insertEntityDatatypeStmt.setString(1, entity.id);
       insertEntityDatatypeStmt.setString(2, entity.datatype);
 
       insertEntityDatatypeStmt.execute();
@@ -47,7 +70,7 @@ public class MySQLInsertEntityDatatype extends MySQLTransaction
         final PreparedStatement insertEntityCollectionStmt =
             prepareStatement(STMT_INSERT_ENTITY_COLLECTION);
 
-        insertEntityCollectionStmt.setInt(1, entity.id);
+        insertEntityCollectionStmt.setString(1, entity.id);
         insertEntityCollectionStmt.setString(2, entity.collection);
 
         insertEntityCollectionStmt.execute();
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java
index becb56a2397fffa323f005507463a586bdecc0cf..cef624dce3a022043a2f86e56acd6ca589d493d1 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityProperties.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -48,6 +47,17 @@ import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.wrapper.Property;
 
+/**
+ * Insert the entity's properties.
+ *
+ * <p>This implementation transforms a deep tree of properties into a flat representation. This
+ * transformation is a MySQL-backend implementation detail and should not be leaked to the clients.
+ *
+ * <p>The reverse transformation happens in MySQLRetrieveProperties.
+ *
+ * @see {@link MySQLRetrieveProperties}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLInsertEntityProperties extends MySQLTransaction
     implements InsertEntityPropertiesImpl {
 
@@ -89,9 +99,9 @@ public class MySQLInsertEntityProperties extends MySQLTransaction
     try {
       final PreparedStatement stmt = prepareStatement(STMT_INSERT_ENTITY_PROPERTY);
 
-      stmt.setInt(1, domain.toInteger());
-      stmt.setInt(2, entity.toInteger());
-      stmt.setInt(3, fp.id);
+      stmt.setString(1, domain.toString());
+      stmt.setString(2, entity.toString());
+      stmt.setString(3, fp.id);
       stmt.setString(4, table.toString());
 
       stmt.setString(5, fp.value);
@@ -124,7 +134,7 @@ public class MySQLInsertEntityProperties extends MySQLTransaction
       final FlatProperty fp = new FlatProperty();
       Table table = Table.null_data;
       Long unit_sig = null;
-      fp.id = property.getId().toInteger();
+      fp.id = property.getId().toString();
       fp.idx = property.getPIdx();
       fp.status = property.getStatementStatus().name();
 
@@ -140,7 +150,7 @@ public class MySQLInsertEntityProperties extends MySQLTransaction
         fp.value = fp.id.toString();
 
         // id is to be the replacement id (an internally used/private id)
-        fp.id = ((ReferenceValue) property.getValue()).getId().toInteger();
+        fp.id = ((ReferenceValue) property.getValue()).getId().toString();
         table = Table.reference_data;
       } else {
 
@@ -215,7 +225,7 @@ public class MySQLInsertEntityProperties extends MySQLTransaction
     }
   }
 
-  public static final String STMT_REGISTER_SUBDOMAIN = "call registerSubdomain(?)";
+  public static final String STMT_REGISTER_SUBDOMAIN = "call registerReplacementIds(?)";
 
   public Deque<EntityID> registerReplacementId(final int domainCount)
       throws SQLException, ConnectionException {
@@ -224,7 +234,7 @@ public class MySQLInsertEntityProperties extends MySQLTransaction
     try (final ResultSet rs = stmt.executeQuery()) {
       final Deque<EntityID> ret = new ArrayDeque<>();
       while (rs.next()) {
-        ret.add(new EntityID(rs.getInt(1)));
+        ret.add(new EntityID(rs.getString(1)));
       }
       return ret;
     }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertParents.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertParents.java
index 61a5e8c48cdc85098e1b0a2f5531c358d6c6058d..0e44c687b05d4184d81f05eeb8640a15b1e88662 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertParents.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertParents.java
@@ -40,8 +40,8 @@ public class MySQLInsertParents extends MySQLTransaction implements InsertParent
   public void execute(final EntityID entity, final EntityID parent) throws TransactionException {
     try {
       final PreparedStatement stmt = prepareStatement(STMT_INSERT_ISA);
-      stmt.setInt(1, entity.toInteger());
-      stmt.setInt(2, parent.toInteger());
+      stmt.setString(1, entity.toString());
+      stmt.setString(2, parent.toString());
       stmt.execute();
     } catch (final Exception e) {
       throw new TransactionException(e);
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
index 27227926156fc9b35ab75473e1efa2cce55f152e..fa70a1453b8dd2f2c761cf3e4e658cb77c5a445f 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -38,9 +37,8 @@ public class MySQLInsertSparseEntity extends MySQLTransaction implements InsertS
     super(access);
   }
 
-  public static final String STMT_INSERT_SPARSE_ENTITY = "call insertEntity(?,?,?,?)";
-  public static final String STMT_INSERT_FILE_PROPERTIES =
-      "INSERT INTO files (file_id, hash, size, path) VALUES (?, unhex(?), ?, ?);";
+  public static final String STMT_INSERT_SPARSE_ENTITY = "call insertEntity(?,?,?,?,?)";
+  public static final String STMT_INSERT_FILE_PROPERTIES = "call setFileProperties(?,?,?,?)";
 
   @Override
   public void execute(final SparseEntity entity) {
@@ -48,29 +46,29 @@ public class MySQLInsertSparseEntity extends MySQLTransaction implements InsertS
       final PreparedStatement insertEntityStmt = prepareStatement(STMT_INSERT_SPARSE_ENTITY);
       final PreparedStatement insertFilePropsStmt = prepareStatement(STMT_INSERT_FILE_PROPERTIES);
 
-      insertEntityStmt.setString(1, entity.name);
-      insertEntityStmt.setString(2, entity.description);
-      insertEntityStmt.setString(3, entity.role);
-      insertEntityStmt.setString(4, entity.acl);
+      insertEntityStmt.setString(1, entity.id);
+      insertEntityStmt.setString(2, entity.name);
+      insertEntityStmt.setString(3, entity.description);
+      insertEntityStmt.setString(4, entity.role);
+      insertEntityStmt.setString(5, entity.acl);
 
       try (final ResultSet rs = insertEntityStmt.executeQuery()) {
         if (rs.next()) {
-          entity.id = rs.getInt("EntityID");
           entity.versionId = DatabaseUtils.bytes2UTF8(rs.getBytes("Version"));
         } else {
-          throw new TransactionException("Didn't get new EntityID back.");
+          throw new TransactionException("Didn't get the version id back.");
         }
       }
 
       if (entity.filePath != null) {
-        insertFilePropsStmt.setInt(1, entity.id);
+        insertFilePropsStmt.setString(1, entity.id);
+        insertFilePropsStmt.setString(2, entity.filePath);
+        insertFilePropsStmt.setLong(3, entity.fileSize);
         if (entity.fileHash != null) {
-          insertFilePropsStmt.setString(2, entity.fileHash);
+          insertFilePropsStmt.setString(4, entity.fileHash);
         } else {
-          insertFilePropsStmt.setNull(2, Types.VARCHAR);
+          insertFilePropsStmt.setNull(4, Types.VARCHAR);
         }
-        insertFilePropsStmt.setLong(3, entity.fileSize);
-        insertFilePropsStmt.setString(4, entity.filePath);
         insertFilePropsStmt.execute();
       }
     } catch (final SQLIntegrityConstraintViolationException exc) {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertTransactionHistory.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertTransactionHistory.java
index 0832790a0b56446570fbd7b9c3a4383390c443a7..155cb2d0b8c8db4948b4a2970785eecb636dcf9b 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertTransactionHistory.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLInsertTransactionHistory.java
@@ -56,7 +56,7 @@ public class MySQLInsertTransactionHistory extends MySQLTransaction
       logStmt.setString(3, user);
       logStmt.setLong(4, seconds);
       logStmt.setInt(5, nanos);
-      logStmt.setInt(6, entity.toInteger());
+      logStmt.setString(6, entity.toString());
       logStmt.execute();
     } catch (final Exception e) {
       throw new TransactionException(e);
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLIsSubType.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLIsSubType.java
index f6c2daf8d4a0bf4defcaa550cf715032d57cd9cd..0d469a79482069d1f19de3931433e90faf5c667a 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLIsSubType.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLIsSubType.java
@@ -43,8 +43,8 @@ public class MySQLIsSubType extends MySQLTransaction implements IsSubTypeImpl {
     try {
       final PreparedStatement isSubtypeStmt = prepareStatement(STMT_IS_SUBTYPE);
 
-      isSubtypeStmt.setInt(1, child.toInteger());
-      isSubtypeStmt.setInt(2, parent.toInteger());
+      isSubtypeStmt.setString(1, child.toString());
+      isSubtypeStmt.setString(2, parent.toString());
 
       final ResultSet rs = isSubtypeStmt.executeQuery();
       try {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLListUsers.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLListUsers.java
index 83ebffe679e6625da720fd2933a5d8defb7264c3..3b68c45d0ff60473ae837f3c9ebc17ae82e68c2d 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLListUsers.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLListUsers.java
@@ -53,8 +53,8 @@ public class MySQLListUsers extends MySQLTransaction implements ListUsersImpl {
           user.name = rs.getString("name");
           user.realm = rs.getString("realm");
           user.email = rs.getString("email");
-          user.entity = rs.getInt("entity");
-          if (user.entity == 0) {
+          user.entity = rs.getString("entity");
+          if (user.entity.isBlank() || user.entity.equals("0")) {
             user.entity = null;
           }
           user.status = UserStatus.valueOf(rs.getString("status"));
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java
index 23050da87e324026be1eefa02690959d0a0590cc..d3b9167e13fb92df3b69e9418f9d3c0d61458233 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java
@@ -36,6 +36,7 @@ public class MySQLLogUserVisit extends MySQLTransaction implements LogUserVisitI
 
   public static final String LOG_USER_VISIT =
       "SELECT status FROM user_info WHERE realm = ? AND name = ?";
+
   // TODO Replace by "UPDATE user_info SET last_seen = ?";
 
   /** Return true if this is not the first visit of this user. */
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java
index 9a2ea81629853e3baf9de7757e1abe6c8f01fe28..55b8f194ea0be90b5a77fa0c50930c836c48b3f7 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAll.java
@@ -75,7 +75,7 @@ public class MySQLRetrieveAll extends MySQLTransaction implements RetrieveAllImp
           final String acl = DatabaseUtils.bytes2UTF8(rs.getBytes("ACL"));
           if (EntityACL.deserialize(acl)
               .isPermitted(SecurityUtils.getSubject(), EntityPermission.RETRIEVE_ENTITY)) {
-            ret.add(new EntityID(rs.getInt("ID")));
+            ret.add(new EntityID(rs.getString("ID")));
           }
         }
         return ret;
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAllUncheckedFiles.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAllUncheckedFiles.java
index 09a4e7c2edabea49617224fdb9159116f2cd742b..cfbf2281b920382b30be10f2ff9e8a0ab16728ab 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAllUncheckedFiles.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveAllUncheckedFiles.java
@@ -51,7 +51,7 @@ public class MySQLRetrieveAllUncheckedFiles extends MySQLTransaction
       final ResultSet rs = stmt.executeQuery();
       if (rs.next()) {
         final SparseEntity first = new SparseEntity();
-        first.id = rs.getInt("file_id");
+        first.id = rs.getString("file_id");
         first.filePath = rs.getString("path");
         first.fileHash = rs.getString("file_hash");
         first.fileSize = rs.getLong("size");
@@ -71,7 +71,7 @@ public class MySQLRetrieveAllUncheckedFiles extends MySQLTransaction
             try {
               if (rs.next()) {
                 this.next = new SparseEntity();
-                this.next.id = rs.getInt("file_id");
+                this.next.id = rs.getString("file_id");
                 this.next.filePath = rs.getString("path");
                 this.next.fileHash = rs.getString("file_hash");
                 this.next.fileSize = rs.getLong("size");
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveCurrentMaxId.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveCurrentMaxId.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f56324f84cea47081f4f9901f10c772508309d4
--- /dev/null
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveCurrentMaxId.java
@@ -0,0 +1,61 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.database.backend.implementation.MySQL;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import org.caosdb.server.database.access.Access;
+import org.caosdb.server.database.backend.interfaces.RetrieveCurrentMaxIdImpl;
+import org.caosdb.server.database.exceptions.TransactionException;
+
+/**
+ * Implements {@link RetrieveCurrentMaxIdImpl} for a MySQL/MariaDB back-end.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class MySQLRetrieveCurrentMaxId extends MySQLTransaction
+    implements RetrieveCurrentMaxIdImpl {
+
+  public MySQLRetrieveCurrentMaxId(Access access) {
+    super(access);
+  }
+
+  public static final String STMT =
+      "SELECT max(CAST(entity_id AS UNSIGNED INT)) AS max_id FROM transaction_log WHERE transaction='Insert'";
+
+  @Override
+  public Integer execute() {
+    try {
+      try (PreparedStatement stmt = prepareStatement(STMT)) {
+
+        try (ResultSet rs = stmt.executeQuery()) {
+          if (rs.next()) {
+            return rs.getInt("max_id");
+          } else {
+            return 100;
+          }
+        }
+      }
+    } catch (SQLException | ConnectionException e) {
+      throw new TransactionException(e);
+    }
+  }
+}
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveEntityACL.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveEntityACL.java
index 5db8ed7597b1c0d357273848fb7c36febdcfed13..716b7ff65814d1464ccac39ef64af275996e096d 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveEntityACL.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveEntityACL.java
@@ -39,9 +39,9 @@ public class MySQLRetrieveEntityACL extends MySQLTransaction implements Retrieve
       "SELECT a.acl FROM entities AS e LEFT JOIN entity_acl AS a ON (a.id = e.acl) WHERE e.id = ? LIMIT 1";
 
   @Override
-  public VerySparseEntity execute(Integer id) {
+  public VerySparseEntity execute(String id) {
     try (PreparedStatement stmt = prepareStatement(STMT)) {
-      stmt.setInt(1, id);
+      stmt.setString(1, id);
       ResultSet rs = stmt.executeQuery();
       if (rs.next()) {
         VerySparseEntity result = new VerySparseEntity();
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
index 1e2a6621d2fb85a5a5260b1a607670e970f54701..6f48e755537b7cd891d0254c9f2255f537a1d10a 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveParents.java
@@ -49,7 +49,7 @@ public class MySQLRetrieveParents extends MySQLTransaction implements RetrievePa
       try {
         final PreparedStatement prepareStatement = prepareStatement(stmtStr);
 
-        prepareStatement.setInt(1, id.toInteger());
+        prepareStatement.setString(1, id.toString());
         if (version == null) {
           prepareStatement.setNull(2, Types.VARBINARY);
         } else {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
index 100df4ce72ebae75d3022866b345bacc9752ad91..97fe4dc1b2453aac7e501db796da23ae25f2e317 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveProperties.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,11 +18,10 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
+import com.mysql.cj.jdbc.exceptions.MysqlDataTruncation;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -34,6 +34,16 @@ import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.database.proto.ProtoProperty;
 import org.caosdb.server.entity.EntityID;
 
+/**
+ * Retrieve the entity's properties.
+ *
+ * <p>This implemation transforms the flat structure of properties which is stored in the back end
+ * to a deep tree of properties (if applicable) which is the reverse transformation to that
+ * happening in MySQLInsertEntityProperties.
+ *
+ * @see {@link MySQLInsertEntityProperties}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLRetrieveProperties extends MySQLTransaction implements RetrievePropertiesImpl {
 
   public MySQLRetrieveProperties(final Access access) {
@@ -50,12 +60,12 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
       final PreparedStatement prepareStatement = prepareStatement(stmtStr);
 
       final List<ProtoProperty> propsStage1 =
-          retrieveFlatPropertiesStage1(0, entity.toInteger(), version, prepareStatement);
+          retrieveFlatPropertiesStage1("0", entity.toString(), version, prepareStatement);
 
       for (final ProtoProperty p : propsStage1) {
 
         p.subProperties =
-            retrieveFlatPropertiesStage1(entity.toInteger(), p.id, version, prepareStatement);
+            retrieveFlatPropertiesStage1(entity.toString(), p.id, version, prepareStatement);
       }
       return DatabaseUtils.transformToDeepPropertyTree(propsStage1, isHead);
     } catch (final SQLException e) {
@@ -66,18 +76,11 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
   }
 
   private List<ProtoProperty> retrieveFlatPropertiesStage1(
-      final Integer domain,
-      final Integer entity,
-      final String version,
-      final PreparedStatement stmt)
+      final String domain, final String entity, final String version, final PreparedStatement stmt)
       throws SQLException, ConnectionException {
-    if (domain != null && domain >= 0) {
-      stmt.setInt(1, domain);
-    } else {
-      stmt.setInt(1, 0);
-    }
 
-    stmt.setInt(2, entity);
+    stmt.setString(1, domain);
+    stmt.setString(2, entity);
     if (version == null) {
       stmt.setNull(3, Types.VARBINARY);
     } else {
@@ -94,15 +97,19 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
 
       final PreparedStatement retrieveOverrides = prepareStatement(stmtStr2);
 
-      retrieveOverrides(domain, entity, version, retrieveOverrides, properties);
+      if (properties != null & !properties.isEmpty()) {
+        retrieveOverrides(domain, entity, version, retrieveOverrides, properties);
+      }
 
       return properties;
+    } catch (MysqlDataTruncation e) {
+      throw e;
     }
   }
 
   private void retrieveOverrides(
-      final Integer domain,
-      final Integer entity,
+      final String domain,
+      final String entity,
       final String version,
       final PreparedStatement retrieveOverrides,
       final List<ProtoProperty> props)
@@ -110,8 +117,8 @@ public class MySQLRetrieveProperties extends MySQLTransaction implements Retriev
 
     ResultSet rs = null;
     try {
-      retrieveOverrides.setInt(1, domain);
-      retrieveOverrides.setInt(2, entity);
+      retrieveOverrides.setString(1, domain);
+      retrieveOverrides.setString(2, entity);
       if (version == null) {
         retrieveOverrides.setNull(3, Types.VARBINARY);
       } else {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
index 1ab95ae7afc756742475ff2f3c79eddfd632aae9..5e96353af089d469faef2ef5c970fb4de725fab0 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveQueryTemplateDefinition.java
@@ -46,7 +46,7 @@ public class MySQLRetrieveQueryTemplateDefinition extends MySQLTransaction
     try {
 
       final PreparedStatement stmt = prepareStatement(STMT_RETRIEVE_QUERY_TEMPLATE_DEF);
-      stmt.setInt(1, id.toInteger());
+      stmt.setString(1, id.toString());
       if (version == null) {
         stmt.setNull(2, Types.VARBINARY);
       } else {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
index 48cd84b3869262ba7f1d8129fdde2335bed6cd8e..c4a9b6262a7506c38b8dff6215682014203da1c1 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveSparseEntity.java
@@ -51,7 +51,7 @@ public class MySQLRetrieveSparseEntity extends MySQLTransaction
     try {
       final PreparedStatement preparedStatement = prepareStatement(stmtStr);
 
-      preparedStatement.setInt(1, id.toInteger());
+      preparedStatement.setString(1, id.toString());
       if (version == null) {
         preparedStatement.setNull(2, Types.VARBINARY);
       } else {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java
index 40f036f1d63753c0be9e6153f741db7d4f9d04ad..b149fae264549f88c21d996f854662401d744beb 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveUser.java
@@ -66,7 +66,7 @@ public class MySQLRetrieveUser extends MySQLTransaction implements RetrieveUserI
           if (rs.getString("entity") == null) {
             ret.entity = null;
           } else {
-            ret.entity = rs.getInt("entity");
+            ret.entity = rs.getString("entity");
           }
         }
       } finally {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java
index 6c4c2629a5effee25128f478bef20f5558a027ba..9493b382ec61f11953f1ba045f5c914b7502f690 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveVersionHistory.java
@@ -53,7 +53,7 @@ public class MySQLRetrieveVersionHistory extends MySQLTransaction
     final HashMap<String, VersionHistoryItem> result = new HashMap<>();
     try {
       final PreparedStatement s = prepareStatement(VERSION_HISTORY_STMT);
-      s.setInt(1, entityId.toInteger());
+      s.setString(1, entityId.toString());
       final ResultSet rs = s.executeQuery();
 
       while (rs.next()) {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileCheckedTimestampImpl.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileCheckedTimestampImpl.java
index 18d7d9b7f510f5cb24e1fe844ac4caac86ff4913..b08d05170dbc45168f597181389c18a1454ee103 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileCheckedTimestampImpl.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileCheckedTimestampImpl.java
@@ -43,7 +43,7 @@ public class MySQLSetFileCheckedTimestampImpl extends MySQLTransaction
     try {
       final PreparedStatement stmt = getMySQLHelper().prepareStatement(STMT_SET_TS);
       stmt.setLong(1, ts);
-      stmt.setInt(2, id.toInteger());
+      stmt.setString(2, id.toString());
     } catch (final SQLException e) {
       throw new TransactionException(e);
     } catch (final ConnectionException e) {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileChecksum.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileChecksum.java
index fb6d4188c835fbc895ed4d5e427bb1b2bbc0bb4c..79c7253103f1ed578c45102ee2bf1a920b2c6049 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileChecksum.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetFileChecksum.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
 import java.sql.PreparedStatement;
@@ -10,7 +29,7 @@ import org.caosdb.server.entity.EntityID;
 /**
  * Implements {@link SetFileChecksumImpl} for a MySQL/MariaDB back-end.
  *
- * @author Timm Fitschen (t.fitschen@indiscale.com)
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class MySQLSetFileChecksum extends MySQLTransaction implements SetFileChecksumImpl {
 
@@ -19,13 +38,13 @@ public class MySQLSetFileChecksum extends MySQLTransaction implements SetFileChe
   }
 
   public static final String STMT_SET_CHECKSUM =
-      "UPDATE files SET hash = unhex(?) WHERE file_id = ?";
+      "UPDATE files SET hash = unhex(?) WHERE EXISTS (SELECT 1 FROM entity_ids AS eids WHERE eids.id = ? AND eids.internal_id = files.file_id)";
 
   @Override
   public void execute(final EntityID id, final String checksum) {
     try {
       final PreparedStatement stmt = prepareStatement(STMT_SET_CHECKSUM);
-      stmt.setInt(2, id.toInteger());
+      stmt.setString(2, id.toString());
       stmt.setString(1, checksum);
       stmt.execute();
     } catch (SQLException | ConnectionException e) {
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetQueryTemplateDefinition.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetQueryTemplateDefinition.java
index f3ded949383c7d250d4ad58e6ae964aa9f96324c..70293edb974c2f12ba78caefc8474a768774e9d2 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetQueryTemplateDefinition.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLSetQueryTemplateDefinition.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -29,6 +28,11 @@ import org.caosdb.server.database.backend.interfaces.SetQueryTemplateDefinitionI
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.entity.EntityID;
 
+/**
+ * Implements {@link SetQueryTemplateDefinitionImpl} for a MariaDB back-end.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class MySQLSetQueryTemplateDefinition extends MySQLTransaction
     implements SetQueryTemplateDefinitionImpl {
 
@@ -37,13 +41,13 @@ public class MySQLSetQueryTemplateDefinition extends MySQLTransaction
   }
 
   public static final String STMT_INSERT_QUERY_TEMPLATE_DEF =
-      "INSERT INTO query_template_def (id, definition) VALUES (?,?) ON DUPLICATE KEY UPDATE definition=?;";
+      "INSERT INTO query_template_def (id, definition) VALUES ((SELECT internal_id FROM entity_ids WHERE entity_ids.id = ?),?) ON DUPLICATE KEY UPDATE definition=?;";
 
   @Override
   public void insert(final EntityID id, final String definition) {
     try {
       final PreparedStatement stmt = prepareStatement(STMT_INSERT_QUERY_TEMPLATE_DEF);
-      stmt.setInt(1, id.toInteger());
+      stmt.setString(1, id.toString());
       stmt.setString(2, definition);
       stmt.setString(3, definition);
       stmt.execute();
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
index b2d0fb9e3b7615e7e95243a2a7bde2fa99e98ca2..8d2af662f32d2f5a788d6470cf6cd526e15d0976 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateSparseEntity.java
@@ -47,7 +47,7 @@ public class MySQLUpdateSparseEntity extends MySQLTransaction implements UpdateS
     try {
       // file properties;
       final PreparedStatement updateFilePropsStmt = prepareStatement(STMT_UPDATE_FILE_PROPS);
-      updateFilePropsStmt.setInt(1, spe.id);
+      updateFilePropsStmt.setString(1, spe.id);
       if (spe.filePath != null) {
         updateFilePropsStmt.setString(2, spe.filePath);
         updateFilePropsStmt.setLong(3, spe.fileSize);
@@ -65,7 +65,7 @@ public class MySQLUpdateSparseEntity extends MySQLTransaction implements UpdateS
 
       // very sparse entity
       final PreparedStatement updateEntityStmt = prepareStatement(STMT_UPDATE_ENTITY);
-      updateEntityStmt.setInt(1, spe.id);
+      updateEntityStmt.setString(1, spe.id);
       updateEntityStmt.setString(2, spe.name);
       updateEntityStmt.setString(3, spe.description);
       updateEntityStmt.setString(4, spe.role);
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUser.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUser.java
index bd368698956163a8473ead7507aac0ba2b83d552..43f71e386fcad42b4a3e39e14eeedf7cb924a535 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUser.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUser.java
@@ -49,7 +49,7 @@ public class MySQLUpdateUser extends MySQLTransaction implements UpdateUserImpl
       stmt.setString(3, user.status.toString());
       stmt.setString(4, user.email);
       if (user.entity != null) {
-        stmt.setInt(5, user.entity);
+        stmt.setString(5, user.entity);
       } else {
         stmt.setNull(5, Types.INTEGER);
       }
@@ -57,7 +57,7 @@ public class MySQLUpdateUser extends MySQLTransaction implements UpdateUserImpl
       stmt.setString(6, user.status.toString());
       stmt.setString(7, user.email);
       if (user.entity != null) {
-        stmt.setInt(8, user.entity);
+        stmt.setString(8, user.entity);
       } else {
         stmt.setNull(8, Types.INTEGER);
       }
diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java
index 61e431bab60b9973f6aa1f0b824ffc3e3b60744e..8ec47231d7d3644bc4c21a2b2125175a75f4bc97 100644
--- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java
+++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/Replacement.java
@@ -28,6 +28,7 @@ import org.caosdb.server.entity.wrapper.Property;
 enum ReplacementStatus implements StatementStatusInterface {
   REPLACEMENT
 }
+
 /**
  * A wrapper of {@link Property} objects used by the back-end implementation for the MySQL/MariaDB
  * back-end.
diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/GetChildrenImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveCurrentMaxIdImpl.java
similarity index 63%
rename from src/main/java/org/caosdb/server/database/backend/interfaces/GetChildrenImpl.java
rename to src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveCurrentMaxIdImpl.java
index 8b0211a0b56bec22e4823058dfa72c355e59d19d..ca711d52c3983b4f71bf41aa5ef63583430866a8 100644
--- a/src/main/java/org/caosdb/server/database/backend/interfaces/GetChildrenImpl.java
+++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveCurrentMaxIdImpl.java
@@ -1,9 +1,8 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,16 +16,17 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.interfaces;
 
-import java.util.List;
-import org.caosdb.server.database.exceptions.TransactionException;
-import org.caosdb.server.entity.EntityID;
+import org.caosdb.server.database.backend.transaction.RetrieveCurrentMaxId;
 
-public interface GetChildrenImpl extends BackendTransactionImpl {
+/**
+ * Interface for the backend implementation of {@link RetrieveCurrentMaxId}
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public interface RetrieveCurrentMaxIdImpl extends BackendTransactionImpl {
 
-  public abstract List<EntityID> execute(EntityID entity) throws TransactionException;
+  public Integer execute();
 }
diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveEntityACLImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveEntityACLImpl.java
index 230d4d34103603d5499532a7dc1a941cf82068e7..cc61461996dc46ae5ea4a997bd0938587959cd24 100644
--- a/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveEntityACLImpl.java
+++ b/src/main/java/org/caosdb/server/database/backend/interfaces/RetrieveEntityACLImpl.java
@@ -25,5 +25,5 @@ import org.caosdb.server.database.proto.VerySparseEntity;
 
 public interface RetrieveEntityACLImpl extends BackendTransactionImpl {
 
-  public VerySparseEntity execute(Integer id);
+  public VerySparseEntity execute(String id);
 }
diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/GetChildren.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveCurrentMaxId.java
similarity index 51%
rename from src/main/java/org/caosdb/server/database/backend/transaction/GetChildren.java
rename to src/main/java/org/caosdb/server/database/backend/transaction/RetrieveCurrentMaxId.java
index d0e2a809547ad2be4621ccab3f79d793dde70006..4dd76d30cd0cf1c63d5eb8ad48054093f064629f 100644
--- a/src/main/java/org/caosdb/server/database/backend/transaction/GetChildren.java
+++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveCurrentMaxId.java
@@ -1,9 +1,8 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,33 +16,33 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.transaction;
 
-import java.util.List;
 import org.caosdb.server.database.BackendTransaction;
-import org.caosdb.server.database.backend.interfaces.GetChildrenImpl;
-import org.caosdb.server.database.exceptions.TransactionException;
-import org.caosdb.server.entity.EntityID;
-
-public class GetChildren extends BackendTransaction {
+import org.caosdb.server.database.backend.interfaces.RetrieveCurrentMaxIdImpl;
 
-  private final EntityID entity;
-  private List<EntityID> list;
+/**
+ * Retrieve the maximum currently known entity id.
+ *
+ * <p>This is used by the EntityIdRegistry for the legacy ids (i.e. integer ids) to generate
+ * sequential ids which have not been used yet.
+ *
+ * @see {@link EntityIdRegistry}
+ * @see {@link LegacyIds}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class RetrieveCurrentMaxId extends BackendTransaction {
 
-  public GetChildren(final EntityID entity) {
-    this.entity = entity;
-  }
+  private Integer maxId;
 
   @Override
-  public void execute() throws TransactionException {
-    final GetChildrenImpl t = getImplementation(GetChildrenImpl.class);
-    this.list = t.execute(this.entity);
+  protected void execute() {
+    RetrieveCurrentMaxIdImpl t = getImplementation(RetrieveCurrentMaxIdImpl.class);
+    this.maxId = t.execute();
   }
 
-  public List<EntityID> getList() {
-    return this.list;
+  public Integer getCurrentMaxId() {
+    return this.maxId;
   }
 }
diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveEntityACLTransaction.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveEntityACLTransaction.java
index 8ef143b44e292e5b100ff30ca023e91c0adb190e..00f8c51026278d3c3660c798b5b0854aff5900eb 100644
--- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveEntityACLTransaction.java
+++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveEntityACLTransaction.java
@@ -43,7 +43,7 @@ public class RetrieveEntityACLTransaction
   @Override
   public VerySparseEntity executeNoCache() throws TransactionException {
     RetrieveEntityACLImpl t = getImplementation(RetrieveEntityACLImpl.class);
-    return t.execute(getKey().toInteger());
+    return t.execute(getKey().toString());
   }
 
   @Override
diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTransaction.java b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTransaction.java
index eee73735a07cc2e152e0099bf5d027d1413631b4..92f5aa841aed5f759d433076700a8b1ce13e26dc 100644
--- a/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTransaction.java
+++ b/src/main/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTransaction.java
@@ -160,6 +160,7 @@ public class RetrieveFullEntityTransaction extends BackendTransaction {
     }
     return false;
   }
+
   /**
    * Return true iff the parents need to be retrieved.
    *
diff --git a/src/main/java/org/caosdb/server/database/misc/TransactionBenchmark.java b/src/main/java/org/caosdb/server/database/misc/TransactionBenchmark.java
index 397a1f52201727d17b057dc92567893798b63cf5..6b14bd1d627a4dbe1b2ef131f76917586155a385 100644
--- a/src/main/java/org/caosdb/server/database/misc/TransactionBenchmark.java
+++ b/src/main/java/org/caosdb/server/database/misc/TransactionBenchmark.java
@@ -132,6 +132,7 @@ class RootBenchmark extends TransactionBenchmark implements ServerStat {
 
   private static final long serialVersionUID = -95212746021180579L;
   private transient boolean synced = false;
+
   /**
    * Fetch old data (from before last shutdown) and fill it into this instance.
    *
@@ -286,7 +287,8 @@ public abstract class TransactionBenchmark implements Serializable {
 
   protected TransactionBenchmark() {
     stackTraceElements = Thread.currentThread().getStackTrace();
-  };
+  }
+  ;
 
   public Iterable<SubBenchmark> getSubBenchmarks() {
     return this.subBenchmarks.values();
diff --git a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java
index b92d3def38d26f0f5f6cd6a0455d472b8f4f3ccb..b2123ce206ce01acee3ef70b1c22151b94f59bd9 100644
--- a/src/main/java/org/caosdb/server/database/proto/FlatProperty.java
+++ b/src/main/java/org/caosdb/server/database/proto/FlatProperty.java
@@ -27,7 +27,7 @@ import java.io.Serializable;
 public class FlatProperty implements Serializable {
 
   private static final long serialVersionUID = 6039288034435124195L;
-  public Integer id = null;
+  public String id = null;
   public String value = null;
   public String status = null;
   public Integer idx = null;
diff --git a/src/main/java/org/caosdb/server/database/proto/ProtoUser.java b/src/main/java/org/caosdb/server/database/proto/ProtoUser.java
index 643f4250216c7829c8218113a8842ff139b313ec..8b2d97a85044881d61fa6ea795443ae13f3cabc2 100644
--- a/src/main/java/org/caosdb/server/database/proto/ProtoUser.java
+++ b/src/main/java/org/caosdb/server/database/proto/ProtoUser.java
@@ -36,7 +36,7 @@ public class ProtoUser implements Serializable {
   public UserStatus status = null;
   public String name = null;
   public String email = null;
-  public Integer entity = null;
+  public String entity = null;
   public String realm = null;
   public HashSet<String> roles = null;
 }
diff --git a/src/main/java/org/caosdb/server/database/proto/VerySparseEntity.java b/src/main/java/org/caosdb/server/database/proto/VerySparseEntity.java
index 8f32bf52038a00275568688b016b830b19fba5f0..5ceca456abc58d945599cc978987eca783637f95 100644
--- a/src/main/java/org/caosdb/server/database/proto/VerySparseEntity.java
+++ b/src/main/java/org/caosdb/server/database/proto/VerySparseEntity.java
@@ -35,7 +35,7 @@ public class VerySparseEntity implements Serializable {
 
   private static final long serialVersionUID = 7370925076064714740L;
 
-  public Integer id = null;
+  public String id = null;
   public String name = null;
   public String description = null;
   public String role = null;
diff --git a/src/main/java/org/caosdb/server/datatype/AbstractEnumValue.java b/src/main/java/org/caosdb/server/datatype/AbstractEnumValue.java
index be88002543155771d2937e216c64d52931051c25..ffe630baa1e519df2044a487ea3ad0ffc4c4bd34 100644
--- a/src/main/java/org/caosdb/server/datatype/AbstractEnumValue.java
+++ b/src/main/java/org/caosdb/server/datatype/AbstractEnumValue.java
@@ -19,7 +19,9 @@
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  */
 
-/** @review Daniel Hornung 2022-03-04 */
+/**
+ * @review Daniel Hornung 2022-03-04
+ */
 package org.caosdb.server.datatype;
 
 import com.google.common.base.Objects;
diff --git a/src/main/java/org/caosdb/server/datatype/CollectionValue.java b/src/main/java/org/caosdb/server/datatype/CollectionValue.java
index fc94f660490284e560a34d1c407e2d74c51f6358..9fb8c6b3012dd4e9a3fa263aab149a92ce1c7643 100644
--- a/src/main/java/org/caosdb/server/datatype/CollectionValue.java
+++ b/src/main/java/org/caosdb/server/datatype/CollectionValue.java
@@ -21,7 +21,9 @@
  * ** end header
  */
 
-/** @review Daniel Hornung 2022-03-04 */
+/**
+ * @review Daniel Hornung 2022-03-04
+ */
 package org.caosdb.server.datatype;
 
 import java.util.ArrayList;
diff --git a/src/main/java/org/caosdb/server/datatype/ReferenceValue.java b/src/main/java/org/caosdb/server/datatype/ReferenceValue.java
index a24e2ddfda7faf333fd7d7f64420d4a6c7fdc290..e07b1b807c3226cb5bc074aeafd4d8c712ce2ec1 100644
--- a/src/main/java/org/caosdb/server/datatype/ReferenceValue.java
+++ b/src/main/java/org/caosdb/server/datatype/ReferenceValue.java
@@ -1,5 +1,4 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
@@ -20,11 +19,11 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
-/** @review Daniel Hornung 2022-03-04 */
+/**
+ * @review Daniel Hornung 2022-03-04
+ */
 package org.caosdb.server.datatype;
 
 import java.util.Objects;
@@ -41,7 +40,13 @@ import org.jdom2.Element;
  * <p>Differently from other properties, they may be versioned, i.e. they may reference to a
  * specific version of an entity.
  *
- * <p>TODO: Ways to specify a reference value, what are the consequences of versioned references?
+ * <p>Ways to specify a reference value: {id}@{version} using either the version id (a hex'ed sha256
+ * string) or "HEAD", "HEAD~1", "HEAD~2" and so on. Note: "HEAD" always means the "HEAD"
+ * <i>after</i> the transaction. So, if you are changing the referenced entity in the same
+ * transaction and you want to reference the entity in the version before the change you need to use
+ * "HEAD~1" because that is the old version of the future.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class ReferenceValue implements SingleValue {
   private EntityInterface entity = null;
@@ -66,7 +71,7 @@ public class ReferenceValue implements SingleValue {
       throw ServerMessages.DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES;
     } else {
       try {
-        return new ReferenceValue(Integer.parseInt(reference.toString()));
+        return new ReferenceValue(reference.toString());
       } catch (final NumberFormatException e) {
         return new ReferenceValue(reference.toString());
       }
@@ -81,9 +86,9 @@ public class ReferenceValue implements SingleValue {
   public static ReferenceValue parseIdVersion(final String str) {
     final String[] split = str.split("@", 2);
     if (split.length == 2) {
-      return new ReferenceValue(Integer.parseInt(split[0]), split[1]);
+      return new ReferenceValue(split[0], split[1]);
     } else {
-      return new ReferenceValue(Integer.parseInt(str));
+      return new ReferenceValue(str);
     }
   }
 
@@ -150,14 +155,13 @@ public class ReferenceValue implements SingleValue {
   /** If the reference is given by name, versioning is not possible (at the moment). */
   public ReferenceValue(final String name) {
     this.name = name;
+    this.id = new EntityID(name);
   }
 
-  public ReferenceValue(final int id, final String name) {
-    this(new EntityID(id), name);
-  }
-
-  public ReferenceValue(final int id) {
-    this(new EntityID(id));
+  public ReferenceValue(String name, String version) {
+    this.name = name;
+    this.id = new EntityID(name);
+    this.version = version;
   }
 
   public final EntityInterface getEntity() {
diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java
index 614397c50526606176fc50b06e2f07e76cbfb9ff..b27eaa28e5111d783d1d8d3779f36a1938898173 100644
--- a/src/main/java/org/caosdb/server/entity/Entity.java
+++ b/src/main/java/org/caosdb/server/entity/Entity.java
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  *   Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 - 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020 - 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.entity;
 
@@ -62,6 +59,17 @@ import org.caosdb.server.utils.TransactionLogMessage;
 import org.caosdb.unit.Unit;
 import org.jdom2.Element;
 
+/**
+ * Abstract base class for all the important entity classes.
+ *
+ * <p>This is the central data class of the server. It represents Records, RecordTypes, Properties,
+ * and Files.
+ *
+ * <p>This class holds the messages and other transient information as well as the actual data that
+ * is being retrieved from or written to the back-end during a transaction.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public abstract class Entity extends AbstractObservable implements EntityInterface {
 
   public static final String DATATYPE_CHANGED_EVENT = "DatatypeChangedEvent";
@@ -73,7 +81,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
   private String name = null;
   private String description = null;
   private Value value = null;
-  private final EntityID domain = new EntityID(0);
+  private final EntityID domain = new EntityID("0");
   private final EntityID id = new EntityID();
   private AbstractDatatype datatype = null;
   private final ParentContainer parents = new ParentContainer(this);
@@ -349,7 +357,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
   @Override
   public SparseEntity getSparseEntity() {
     final SparseEntity ret = new SparseEntity();
-    ret.id = getId().toInteger();
+    ret.id = getId().toString();
     ret.name = getName();
     ret.description = getDescription();
     ret.acl = getEntityACL().serialize();
@@ -646,13 +654,7 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
 
     // Parse ID. Generate error if it isn't an integer.
     if (element.getAttribute("id") != null && !element.getAttributeValue("id").equals("")) {
-      try {
-        setId(new EntityID(Integer.parseInt(element.getAttributeValue("id"))));
-      } catch (final NumberFormatException e) {
-        addInfo("Id was " + element.getAttributeValue("id") + ".");
-        addError(ServerMessages.PARSING_FAILED);
-        setEntityStatus(EntityStatus.UNQUALIFIED);
-      }
+      this.setId(element.getAttributeValue("id"));
     }
 
     // Parse NAME.
@@ -727,6 +729,9 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
         // record.
 
         final Property property = new Property(new WritableEntity(pe, Role.Property));
+
+        // Ignore parents of properties
+        property.getParents().clear();
         property.setPIdx(pidx++);
         addProperty(property);
       } else if (pe.getName().equalsIgnoreCase("Parent")) {
diff --git a/src/main/java/org/caosdb/server/entity/EntityID.java b/src/main/java/org/caosdb/server/entity/EntityID.java
index 6a2d2ca368088e54c2f3c77ae669c6feda07bb4e..9f61127db2969578300fbe2f12091c0f9f258d90 100644
--- a/src/main/java/org/caosdb/server/entity/EntityID.java
+++ b/src/main/java/org/caosdb/server/entity/EntityID.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2022 - 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2022 - 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.entity;
 
 import java.io.Serializable;
@@ -11,39 +30,37 @@ import java.util.Objects;
  * <p>It also allows to link entities together, e.g. an Entity's Property with the corresponding
  * abstract Property, even when the abstract Property does not have a valid ID yet (during bulk
  * inserts).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class EntityID implements Serializable {
 
-  private static final long serialVersionUID = -9092133023135548179L;
+  private static final long serialVersionUID = -9062285447437546105L;
 
-  public static final EntityID DEFAULT_DOMAIN = new EntityID(0);
-  private Integer i = null;
+  public static final EntityID DEFAULT_DOMAIN = new EntityID("0");
+  private String id = null;
   private EntityID link = null;
 
   public EntityID() {}
 
-  public EntityID(final Integer id) {
-    this.i = id;
+  public EntityID(final String id) {
+    this.id = id;
   }
 
-  public void setId(final Integer i) {
-    this.i = i;
-  }
-
-  public Integer toInteger() {
-    if (this.link != null) {
-      return this.link.toInteger();
-    }
-    return this.i;
+  public void setId(final String id) {
+    this.id = id;
   }
 
   @Override
   public String toString() {
-    return toInteger().toString();
+    if (this.link != null) {
+      return this.link.toString();
+    }
+    return this.id;
   }
 
   boolean hasId() {
-    return this.i != null || this.link != null && this.link.hasId();
+    return this.id != null || this.link != null && this.link.hasId();
   }
 
   public void link(final EntityInterface entity) {
@@ -57,7 +74,7 @@ public class EntityID implements Serializable {
   @Override
   public boolean equals(final Object obj) {
     if (obj instanceof EntityID) {
-      return Objects.equals(((EntityID) obj).toInteger(), this.toInteger());
+      return Objects.equals(((EntityID) obj).toString(), this.toString());
     }
     return false;
   }
@@ -65,16 +82,20 @@ public class EntityID implements Serializable {
   @Override
   public int hashCode() {
     if (this.hasId()) {
-      return toInteger();
+      return toString().hashCode();
     }
     return super.hashCode();
   }
 
   public boolean isTemporary() {
-    return toInteger() < 0;
+    return toString().startsWith("-");
   }
 
   public static boolean isReserved(final EntityID id) {
-    return id.toInteger() < 100;
+    try {
+      return id.hasId() && Integer.parseInt(id.toString()) < 100;
+    } catch (NumberFormatException e) {
+      return false;
+    }
   }
 }
diff --git a/src/main/java/org/caosdb/server/entity/EntityIdRegistry.java b/src/main/java/org/caosdb/server/entity/EntityIdRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4e1158447decf9f98ece6f4de805919b404a5c5
--- /dev/null
+++ b/src/main/java/org/caosdb/server/entity/EntityIdRegistry.java
@@ -0,0 +1,80 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.entity;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import org.caosdb.server.database.exceptions.TransactionException;
+import org.caosdb.server.transaction.Transaction;
+
+/**
+ * An abstract layer for managing entity ids.
+ *
+ * <p>That is, checking whether something is a well-formed id, generating well-formed ids and more.
+ *
+ * <p>This class follows a Strategy Pattern. The actual implemenation can be found in one of the
+ * implementations of the {@link EntityIdRegistryStrategy} interface.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class EntityIdRegistry {
+
+  private EntityIdRegistryStrategy strategy;
+
+  public EntityIdRegistry(Transaction<?> t) {
+    // This is the place where we will inject the new string id behavior in the
+    // future:
+    //
+    // this("org.caosdb.server.entity.StringIds", t);
+    this("org.caosdb.server.entity.LegacyIds", t);
+  }
+
+  public EntityIdRegistry(EntityIdRegistryStrategy strategy) {
+    this.strategy = strategy;
+  }
+
+  /** Return a well-formed, new and unused entity id. */
+  public String generate() {
+    return this.strategy.generate();
+  }
+
+  public EntityIdRegistry(String strategy, Transaction<?> t) {
+    try {
+      @SuppressWarnings("unchecked")
+      Class<? extends EntityIdRegistry> clazz =
+          (Class<? extends EntityIdRegistry>) Class.forName(strategy);
+      Constructor<?> constructor = clazz.getConstructor(Transaction.class);
+      this.strategy = (EntityIdRegistryStrategy) constructor.newInstance(t);
+    } catch (ClassNotFoundException
+        | NoSuchMethodException
+        | SecurityException
+        | InstantiationException
+        | IllegalAccessException
+        | IllegalArgumentException
+        | InvocationTargetException e) {
+      throw new TransactionException(e);
+    }
+  }
+
+  /** Return true if the id is a well-formed id. */
+  public boolean matchIdPattern(String id) {
+    return this.strategy.matchIdPattern(id);
+  }
+}
diff --git a/src/main/java/org/caosdb/server/entity/EntityIdRegistryStrategy.java b/src/main/java/org/caosdb/server/entity/EntityIdRegistryStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..e70f4f52d2e402e62d3442bfe4af91652247216b
--- /dev/null
+++ b/src/main/java/org/caosdb/server/entity/EntityIdRegistryStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.entity;
+
+import org.caosdb.server.transaction.Transaction;
+
+/**
+ * Strategy interface for {@link EntityIdRegistry}.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public abstract class EntityIdRegistryStrategy {
+
+  private Transaction<?> transaction;
+
+  public EntityIdRegistryStrategy(Transaction<?> transaction) {
+    this.transaction = transaction;
+  }
+
+  public abstract String generate();
+
+  public Transaction<?> getTransaction() {
+    return transaction;
+  }
+
+  public abstract boolean matchIdPattern(String id);
+}
diff --git a/src/main/java/org/caosdb/server/entity/EntityInterface.java b/src/main/java/org/caosdb/server/entity/EntityInterface.java
index ba77b5c4ac8b5c833d2046dec506655531ff62cb..4a74920e7ac35d9d503de3802fbae10b2a7eaa3f 100644
--- a/src/main/java/org/caosdb/server/entity/EntityInterface.java
+++ b/src/main/java/org/caosdb/server/entity/EntityInterface.java
@@ -194,4 +194,8 @@ public interface EntityInterface
   public abstract boolean isReferenceList();
 
   public abstract SerializeFieldStrategy getSerializeFieldStrategy();
+
+  public default void setId(String id) {
+    getId().setId(id);
+  }
 }
diff --git a/src/main/java/org/caosdb/server/entity/LegacyIds.java b/src/main/java/org/caosdb/server/entity/LegacyIds.java
new file mode 100644
index 0000000000000000000000000000000000000000..0454129397b90772a505ad5b791a823eabd3ea97
--- /dev/null
+++ b/src/main/java/org/caosdb/server/entity/LegacyIds.java
@@ -0,0 +1,76 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.entity;
+
+import org.caosdb.server.database.backend.transaction.RetrieveCurrentMaxId;
+import org.caosdb.server.transaction.Transaction;
+
+/**
+ * Implementation of {@link EntityIdRegistryStrategy} which re-implements the legacy integer-based
+ * entity ids.
+ *
+ * <p>This implementation will generate sequences of entity ids and matches all strings which can be
+ * cast to integer as well-formed entity ids.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class LegacyIds extends EntityIdRegistryStrategy {
+
+  private boolean isInit;
+  private Integer currentMaxId;
+
+  public LegacyIds(Transaction<?> t) {
+    super(t);
+    this.isInit = false;
+  }
+
+  private void init() {
+    isInit = true;
+    initCurrentMaxId();
+  }
+
+  private void initCurrentMaxId() {
+    this.currentMaxId =
+        Math.max(
+            101,
+            getTransaction()
+                .execute(new RetrieveCurrentMaxId(), getTransaction().getAccess())
+                .getCurrentMaxId());
+  }
+
+  @Override
+  public String generate() {
+    if (!isInit) {
+      init();
+    }
+    ++currentMaxId;
+    return Integer.toString(++currentMaxId);
+  }
+
+  @Override
+  public boolean matchIdPattern(String id) {
+    try {
+      Integer.parseInt(id);
+      return true;
+    } catch (NumberFormatException e) {
+      return false;
+    }
+  }
+}
diff --git a/src/main/java/org/caosdb/server/entity/MagicTypes.java b/src/main/java/org/caosdb/server/entity/MagicTypes.java
index 39556385235e6b72736bed8dff67a178cfe60aff..6e987af95c0188fa21a50f19d11a493d97bbe8d8 100644
--- a/src/main/java/org/caosdb/server/entity/MagicTypes.java
+++ b/src/main/java/org/caosdb/server/entity/MagicTypes.java
@@ -33,9 +33,9 @@ public enum MagicTypes {
   NAME,
   DESCRIPTION;
 
-  private static final EntityID UNIT_ID = new EntityID(21);
-  private static final EntityID DESCRIPTION_ID = new EntityID(24);
-  private static final EntityID NAME_ID = new EntityID(20);
+  private static final EntityID UNIT_ID = new EntityID("21");
+  private static final EntityID DESCRIPTION_ID = new EntityID("24");
+  private static final EntityID NAME_ID = new EntityID("20");
 
   public EntityID getId() {
     switch (this) {
@@ -51,12 +51,12 @@ public enum MagicTypes {
   }
 
   public static MagicTypes getType(final EntityID id) {
-    switch (id.toInteger()) {
-      case 21:
+    switch (id.toString()) {
+      case "21":
         return UNIT;
-      case 20:
+      case "20":
         return NAME;
-      case 24:
+      case "24":
         return DESCRIPTION;
       default:
         return null;
@@ -82,7 +82,7 @@ public enum MagicTypes {
     final RetrieveContainer container =
         new RetrieveContainer(null, System.currentTimeMillis(), null, null);
     for (final MagicTypes mt : MagicTypes.values()) {
-      container.add(mt.getId());
+      container.add(mt.getId(), null);
     }
     final Retrieve retrieve = new Retrieve(container);
     retrieve.execute();
diff --git a/src/main/java/org/caosdb/server/entity/RetrieveEntity.java b/src/main/java/org/caosdb/server/entity/RetrieveEntity.java
index 2d1ca6f2175ca2377b7f1a73f847a48377cc4694..00a120fbf023024eae8acc5788a9260d020a956d 100644
--- a/src/main/java/org/caosdb/server/entity/RetrieveEntity.java
+++ b/src/main/java/org/caosdb/server/entity/RetrieveEntity.java
@@ -47,6 +47,11 @@ public class RetrieveEntity extends Entity {
     this.setVersion(new Version(version));
   }
 
+  public RetrieveEntity(final EntityID id, String name, final String version) {
+    this(id, version);
+    this.setName(name);
+  }
+
   public RetrieveEntity(final String name, final String version) {
     super(name);
     this.setVersion(new Version(version));
diff --git a/src/main/java/org/caosdb/server/entity/Role.java b/src/main/java/org/caosdb/server/entity/Role.java
index f86158a99be307867c17f136a26e1097e6e7bc5f..a2a97f92546b2e63bac61ff059eeb6128d8bab6b 100644
--- a/src/main/java/org/caosdb/server/entity/Role.java
+++ b/src/main/java/org/caosdb/server/entity/Role.java
@@ -32,7 +32,6 @@ import org.caosdb.server.entity.xml.ToElementStrategy;
 public enum Role {
   RecordType,
   Record,
-  Domain,
   File,
   Property,
   DataType,
diff --git a/src/main/java/org/caosdb/server/entity/StringIds.java b/src/main/java/org/caosdb/server/entity/StringIds.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1f5cb04be995253cd16cdc0a809421122b3dc8e
--- /dev/null
+++ b/src/main/java/org/caosdb/server/entity/StringIds.java
@@ -0,0 +1,51 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.entity;
+
+import java.util.UUID;
+import org.caosdb.server.transaction.Transaction;
+
+/**
+ * Example implementation for string ids based on UUID.
+ *
+ * @see {@link EntityIdRegistryStrategy}
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class StringIds extends EntityIdRegistryStrategy {
+
+  public StringIds(Transaction<?> t) {
+    super(t);
+  }
+
+  @Override
+  public String generate() {
+    return UUID.randomUUID().toString();
+  }
+
+  @Override
+  public boolean matchIdPattern(String id) {
+    try {
+      UUID.fromString(id);
+      return true;
+    } catch (IllegalArgumentException e) {
+      return false;
+    }
+  }
+}
diff --git a/src/main/java/org/caosdb/server/entity/container/Container.java b/src/main/java/org/caosdb/server/entity/container/Container.java
index 1618fbed6a1594891ea3ddc615f48869227f2c92..fdbcbf0de68d77c3eef026ef68d559a69f2f0956 100644
--- a/src/main/java/org/caosdb/server/entity/container/Container.java
+++ b/src/main/java/org/caosdb/server/entity/container/Container.java
@@ -36,9 +36,11 @@ public class Container<T extends EntityInterface> extends ArrayList<T> {
    * Return the entity with the matching id, if it can be found inside this Container, else null.
    */
   public T getEntityById(final EntityID id) {
-    for (final T e : this) {
-      if (e.hasId() && e.getId().equals(id)) {
-        return e;
+    if (id != null) {
+      for (final T e : this) {
+        if (e.hasId() && e.getId().equals(id)) {
+          return e;
+        }
       }
     }
     return null;
diff --git a/src/main/java/org/caosdb/server/entity/container/EntityByIdContainer.java b/src/main/java/org/caosdb/server/entity/container/EntityByIdContainer.java
index a8c3e6a832848903884edda270e003a0c0dd6feb..1e756e3313fc4a816c096351527df7022a79f47b 100644
--- a/src/main/java/org/caosdb/server/entity/container/EntityByIdContainer.java
+++ b/src/main/java/org/caosdb/server/entity/container/EntityByIdContainer.java
@@ -37,7 +37,5 @@ public abstract class EntityByIdContainer extends TransactionContainer {
     super(user, timestamp, srid, flags);
   }
 
-  public abstract void add(EntityID id);
-
   public abstract void add(EntityID id, String version);
 }
diff --git a/src/main/java/org/caosdb/server/entity/container/RetrieveContainer.java b/src/main/java/org/caosdb/server/entity/container/RetrieveContainer.java
index bc0da7c1de2bb876551d29ad7daffb50494f9720..99262f56d15d90ba86fb1a9cd8fd76b90c4dbf22 100644
--- a/src/main/java/org/caosdb/server/entity/container/RetrieveContainer.java
+++ b/src/main/java/org/caosdb/server/entity/container/RetrieveContainer.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.entity.container;
 
@@ -27,7 +26,24 @@ import org.apache.shiro.subject.Subject;
 import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.RetrieveEntity;
 
-public class RetrieveContainer extends EntityByIdContainer {
+/**
+ * A container of entities which are about to be retrieved.
+ *
+ * <p>A suitable name would also be `ReadOnlyEntitiesContainer` because entities in this container
+ * will only be retrieved, not changed, inserted or deleted.
+ *
+ * <p>Because all entities are expected to be existing, all entities can theoretically be identified
+ * via their (valid) entity id (plus version id, if applicable).
+ *
+ * <p>However, sometimes, entities are being retrieved via the name instead of the id. Then the id
+ * has to be resolved first. This happens during the init stage of the owning transaction.
+ *
+ * <p>The container also holds the flags of the current transaction (e.g. cache=false, ACL=true,
+ * ...).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class RetrieveContainer extends TransactionContainer {
 
   private static final long serialVersionUID = 4816050921531043503L;
 
@@ -39,21 +55,11 @@ public class RetrieveContainer extends EntityByIdContainer {
     super(user, timestamp, srid, flags);
   }
 
-  @Override
-  public void add(final EntityID id) {
-    add(new RetrieveEntity(id));
-  }
-
-  public void add(final String name) {
-    add(new RetrieveEntity(name));
-  }
-
-  public void add(final String name, final String version) {
-    add(new RetrieveEntity(name, version));
-  }
-
-  @Override
   public void add(final EntityID id, final String version) {
     add(new RetrieveEntity(id, version));
   }
+
+  public void add(final EntityID id, final String name, final String version) {
+    add(new RetrieveEntity(id, name, version));
+  }
 }
diff --git a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
index d396345508a028700db6fd8e973390fd634e54d9..049f54cd1ded0ece71c7082ddc960c4246ef0b28 100644
--- a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
+++ b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.entity.container;
 
@@ -38,6 +37,12 @@ import org.caosdb.server.query.Query;
 import org.caosdb.server.utils.EntityStatus;
 import org.jdom2.Element;
 
+/**
+ * Base class for transaction containers used by classes such as {@link RetrieveContainer} or {@link
+ * WritableContainer}.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class TransactionContainer extends Container<EntityInterface>
     implements ToElementable, JobTarget {
 
@@ -152,9 +157,11 @@ public class TransactionContainer extends Container<EntityInterface>
    * @param name
    */
   public EntityInterface getEntityByName(final String name) {
-    for (final EntityInterface e : this) {
-      if (e.hasName() && e.getName().equals(name)) {
-        return e;
+    if (name != null) {
+      for (final EntityInterface e : this) {
+        if (e.hasName() && e.getName().equals(name)) {
+          return e;
+        }
       }
     }
     return null;
diff --git a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
index 88429828f27ac843903cfcfc801847c35eedb607..00a433d72c0a00e8e8ef796777bfa016679cbfe6 100644
--- a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
@@ -129,8 +129,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
       result.setEmailSetting(EmailSetting.newBuilder().setEmail(user.email));
     }
     if (user.entity != null) {
-      result.setEntitySetting(
-          EntitySetting.newBuilder().setEntityId(Integer.toString(user.entity)));
+      result.setEntitySetting(EntitySetting.newBuilder().setEntityId(user.entity));
     }
     if (user.roles != null && !user.roles.isEmpty()) {
       result.addAllRoles(user.roles);
diff --git a/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java b/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
index ce8a62210d3c8e849397600fc112cd3103f15df4..49f2facefa845a6deeed5f07bf4fde364891fcb6 100644
--- a/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
+++ b/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
@@ -87,6 +87,7 @@ public class AuthInterceptor implements ServerInterceptor {
     metadata.put(CookieSetter.SET_COOKIE, CookieSetter.EXPIRED_SESSION_COOKIE);
     return metadata;
   }
+
   /**
    * A no-op listener. This class is used for failed authentications. We couldn't return a null
    * instead because the documentation of the {@link ServerInterceptor} explicitely forbids it.
@@ -281,7 +282,7 @@ final class CookieSetter<ReqT, RespT>
   public void sendHeaders(Metadata headers) {
     setSessionCookies(headers);
     super.sendHeaders(headers);
-  };
+  }
 
   private void setSessionCookies(Metadata headers) {
     // if authenticated as a normal user: generate and set session cookie.
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index 030b52544fec858ef3c62c531e9627baf5500551..3386676855dcaaae154a00700b83dc5e2852edff 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,7 +18,6 @@
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  *
  */
-
 package org.caosdb.server.grpc;
 
 import io.grpc.stub.StreamObserver;
@@ -47,11 +46,11 @@ import org.caosdb.api.entity.v1.RetrieveResponse;
 import org.caosdb.api.entity.v1.SelectQueryResult;
 import org.caosdb.api.entity.v1.TransactionRequest;
 import org.caosdb.api.entity.v1.TransactionRequest.WrappedRequestsCase;
-import org.caosdb.api.entity.v1.TransactionResponse;
 import org.caosdb.api.entity.v1.UpdateRequest;
 import org.caosdb.api.entity.v1.UpdateResponse;
 import org.caosdb.server.CaosDBException;
 import org.caosdb.server.entity.DeleteEntity;
+import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.FileProperties;
 import org.caosdb.server.entity.InsertEntity;
@@ -68,6 +67,11 @@ import org.caosdb.server.transaction.UpdateACL;
 import org.caosdb.server.transaction.WriteTransaction;
 import org.caosdb.server.utils.ServerMessages;
 
+/**
+ * Main entry point for the entity transaction service of the servers GRPC API.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBase {
 
   // TODO(tf) let the clients define the time zone of the date time values which are being returned.
@@ -135,15 +139,11 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
       } else { // or ID retrieves.
         final String id = sub_request.getRetrieveRequest().getId();
         if (!id.isBlank()) {
-          try {
-            final RetrieveEntity entity = new RetrieveEntity(grpcToCaosdb.getId(id));
-            if (isFileDownload) {
-              entity.setFlag("download_files", "true");
-            }
-            container.add(entity);
-          } catch (final NumberFormatException e) {
-            // We handle this after the retrieval
+          final RetrieveEntity entity = new RetrieveEntity(new EntityID(id));
+          if (isFileDownload) {
+            entity.setFlag("download_files", "true");
           }
+          container.add(entity);
         }
       }
     }
@@ -193,32 +193,9 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
       }
     }
 
-    // Add those entities which have not been retrieved because they have a string id
-    for (final TransactionRequest sub_request : request.getRequestsList()) {
-      final String id = sub_request.getRetrieveRequest().getId();
-      if (!id.isBlank()) {
-        try {
-          grpcToCaosdb.getId(id);
-        } catch (final NumberFormatException e) {
-          // ID wasn't an integer - the server doesn't support string ids yet, so that entity
-          // cannot exist.
-          builder.addResponses(
-              TransactionResponse.newBuilder()
-                  .setRetrieveResponse(
-                      RetrieveResponse.newBuilder().setEntityResponse(entityDoesNotExist(id))));
-        }
-      }
-    }
     return builder.build();
   }
 
-  private EntityResponse entityDoesNotExist(final String id) {
-    return EntityResponse.newBuilder()
-        .addErrors(caosdbToGrpc.convert(ServerMessages.ENTITY_DOES_NOT_EXIST))
-        .setEntity(Entity.newBuilder().setId(id))
-        .build();
-  }
-
   private String getSRID() {
     return UUID.randomUUID().toString();
   }
@@ -295,29 +272,16 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
           final UpdateRequest updateRequest = subRequest.getUpdateRequest();
           final Entity updateEntity = updateRequest.getEntityRequest().getEntity();
 
-          try {
-            final UpdateEntity entity =
-                new UpdateEntity(
-                    grpcToCaosdb.getId(updateEntity.getId()), // ID is not handled by grpc convert
-                    grpcToCaosdb.convert(updateEntity.getRole()));
-            grpcToCaosdb.convert(updateEntity, entity);
-            addFileUpload(container, entity, updateRequest.getEntityRequest());
-            container.add(entity);
-          } catch (final NumberFormatException e) {
-            // ID wasn't an integer
-            return failedWriteDueToStringId(requests);
-          }
+          final UpdateEntity entity =
+              new UpdateEntity(
+                  new EntityID(updateEntity.getId()), grpcToCaosdb.convert(updateEntity.getRole()));
+          grpcToCaosdb.convert(updateEntity, entity);
+          addFileUpload(container, entity, updateRequest.getEntityRequest());
+          container.add(entity);
           break;
         case DELETE_REQUEST:
           final DeleteRequest deleteRequest = subRequest.getDeleteRequest();
-          try {
-            final DeleteEntity entity = new DeleteEntity(grpcToCaosdb.getId(deleteRequest.getId()));
-            container.add(entity);
-
-          } catch (final NumberFormatException e) {
-            // ID wasn't an integer
-            return failedWriteDueToStringId(requests);
-          }
+          container.add(new DeleteEntity(new EntityID(deleteRequest.getId())));
           break;
         default:
           throw new CaosDBException(
@@ -357,65 +321,6 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     return builder.build();
   }
 
-  /**
-   * 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.v1.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 {
-            grpcToCaosdb.getId(updateEntity.getId());
-          } catch (final NumberFormatException e) {
-            // ID wasn't an integer
-            idResponse.addErrors(caosdbToGrpc.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 {
-            grpcToCaosdb.getId(deleteRequest.getId());
-          } catch (final NumberFormatException e) {
-            // ID wasn't an integer
-            idResponse.addErrors(caosdbToGrpc.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 void addFileUpload(
       final WritableContainer container,
       final EntityInterface entity,
diff --git a/src/main/java/org/caosdb/server/grpc/GRPCServer.java b/src/main/java/org/caosdb/server/grpc/GRPCServer.java
index 73356140b85fb09af93bdca034a69685ce8cd4eb..494ce94706eff75415264b175f58cdaf16a2a442 100644
--- a/src/main/java/org/caosdb/server/grpc/GRPCServer.java
+++ b/src/main/java/org/caosdb/server/grpc/GRPCServer.java
@@ -81,8 +81,11 @@ public class GRPCServer {
    * @throws IOException
    */
   private SslContext buildSslContext()
-      throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException,
-          CertificateException, IOException {
+      throws NoSuchAlgorithmException,
+          UnrecoverableKeyException,
+          KeyStoreException,
+          CertificateException,
+          IOException {
     final KeyManagerFactory kmf =
         KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
     final char[] password =
@@ -112,7 +115,9 @@ public class GRPCServer {
     return builder.build();
   }
 
-  /** @return A list of services which should be added to the gRPC end-point. */
+  /**
+   * @return A list of services which should be added to the gRPC end-point.
+   */
   private List<ServerServiceDefinition> getEnabledServices() {
     final List<ServerServiceDefinition> services = new LinkedList<>();
 
@@ -153,8 +158,11 @@ public class GRPCServer {
    * @throws IOException
    */
   private Server buildServer(final int port, final boolean tls)
-      throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException,
-          CertificateException, IOException {
+      throws UnrecoverableKeyException,
+          NoSuchAlgorithmException,
+          KeyStoreException,
+          CertificateException,
+          IOException {
     final NettyServerBuilder builder = NettyServerBuilder.forPort(port);
 
     if (tls) {
@@ -182,8 +190,12 @@ public class GRPCServer {
    * @throws UnrecoverableKeyException
    */
   public static void startServer()
-      throws IOException, InterruptedException, KeyStoreException, NoSuchAlgorithmException,
-          CertificateException, UnrecoverableKeyException {
+      throws IOException,
+          InterruptedException,
+          KeyStoreException,
+          NoSuchAlgorithmException,
+          CertificateException,
+          UnrecoverableKeyException {
 
     boolean started = false;
     final String port_https_str = getServerProperty(ServerProperties.KEY_GRPC_SERVER_PORT_HTTPS);
diff --git a/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java b/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java
index 0430a795457152141473c2819997ebd1597028fd..587b89662456272d9a81aa910db3b1a962d67499 100644
--- a/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java
+++ b/src/main/java/org/caosdb/server/grpc/GrpcToCaosDBConverters.java
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -16,9 +16,7 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
  */
-
 package org.caosdb.server.grpc;
 
 import java.util.ArrayList;
@@ -64,12 +62,13 @@ import org.caosdb.server.permissions.EntityACLFactory;
 import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
+/**
+ * Utility class for converting GRPC's native objects into our own CaosDB objects.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class GrpcToCaosDBConverters {
 
-  public EntityID getId(final String id) {
-    return new EntityID(Integer.parseInt(id));
-  }
-
   public Role convert(final EntityRole role) {
     switch (role) {
       case ENTITY_ROLE_FILE:
@@ -256,7 +255,7 @@ public class GrpcToCaosDBConverters {
     final Property result = new Property(new RetrieveEntity());
 
     try {
-      result.setId(e.getId().isBlank() ? null : getId(e.getId()));
+      result.setId(e.getId().isBlank() ? null : new EntityID(e.getId()));
     } catch (final NumberFormatException exc) {
       result.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
     }
@@ -314,7 +313,7 @@ public class GrpcToCaosDBConverters {
         new org.caosdb.server.entity.wrapper.Parent(new RetrieveEntity());
 
     try {
-      result.setId(e.getId().isBlank() ? null : getId(e.getId()));
+      result.setId(e.getId().isBlank() ? null : new EntityID(e.getId()));
     } catch (final NumberFormatException exc) {
       result.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
     }
@@ -336,7 +335,7 @@ public class GrpcToCaosDBConverters {
 
   private EntityInterface convert(EntityACL acl) {
     try {
-      EntityID id = getId(acl.getId());
+      EntityID id = new EntityID(acl.getId());
       UpdateEntity result = new UpdateEntity(id);
       result.setEntityACL(convertAcl(acl));
       return result;
diff --git a/src/main/java/org/caosdb/server/jobs/Job.java b/src/main/java/org/caosdb/server/jobs/Job.java
index 9da74edd0db86f6d81a8636020afcdaf3faa9e09..7bb94635ed21c14c80c92d315539dd4fab5416ab 100644
--- a/src/main/java/org/caosdb/server/jobs/Job.java
+++ b/src/main/java/org/caosdb/server/jobs/Job.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  *   Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020-2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,10 +22,10 @@
 package org.caosdb.server.jobs;
 
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import org.apache.shiro.subject.Subject;
@@ -33,9 +33,8 @@ import org.caosdb.server.CaosDBException;
 import org.caosdb.server.database.BackendTransaction;
 import org.caosdb.server.database.backend.transaction.GetIDByName;
 import org.caosdb.server.database.backend.transaction.IsSubType;
-import org.caosdb.server.database.backend.transaction.RetrieveFullEntityTransaction;
-import org.caosdb.server.database.backend.transaction.RetrieveParents;
 import org.caosdb.server.database.backend.transaction.RetrieveSparseEntity;
+import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.database.exceptions.EntityWasNotUniqueException;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.datatype.AbstractCollectionDatatype;
@@ -44,13 +43,12 @@ import org.caosdb.server.datatype.ReferenceDatatype2;
 import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.Message;
-import org.caosdb.server.entity.container.ParentContainer;
+import org.caosdb.server.entity.Version;
 import org.caosdb.server.entity.container.TransactionContainer;
 import org.caosdb.server.entity.wrapper.Parent;
 import org.caosdb.server.jobs.core.JobFailureSeverity;
 import org.caosdb.server.transaction.Transaction;
 import org.caosdb.server.utils.EntityStatus;
-import org.caosdb.server.utils.ServerMessages;
 import org.reflections.Reflections;
 
 /**
@@ -73,7 +71,7 @@ public abstract class Job {
 
   public abstract JobTarget getTarget();
 
-  protected <S, T> HashMap<S, T> getCache(final String name) {
+  protected <S, T> Map<S, T> getCache(final String name) {
     return getTransaction().getCache(name);
   }
 
@@ -89,7 +87,7 @@ public abstract class Job {
     return getTransaction().getTransactor();
   }
 
-  public <K extends BackendTransaction> K execute(final K t) {
+  protected <K extends BackendTransaction> K execute(final K t) {
     return getTransaction().execute(t, getTransaction().getAccess());
   }
 
@@ -185,8 +183,8 @@ public abstract class Job {
       if (targetParent.getId().equals(child.getId())) {
         return true;
       }
-
-    } else if (targetParent.hasName()) {
+    }
+    if (targetParent.hasName()) {
       if (targetParent.getName().equals(child.getName())) {
         return true;
       } else {
@@ -195,13 +193,7 @@ public abstract class Job {
     }
 
     // check direct parents of child
-    ParentContainer directParents;
-    if (child.hasParents()) {
-      directParents = child.getParents();
-    } else {
-      directParents = resolve(child).getParents();
-    }
-    for (final Parent directParent : directParents) {
+    for (final Parent directParent : child.getParents()) {
       EntityInterface resolvedDirectParent = null;
       if (directParent.hasId() && targetParent.hasId()) {
         if (directParent.getId().equals(targetParent.getId())) {
@@ -231,78 +223,73 @@ public abstract class Job {
   }
 
   protected final boolean isValidSubType(final EntityID child, final EntityID parent) {
-    if (!"false".equals(getContainer().getFlags().get("cache"))) {
-      final HashMap<String, Boolean> isSubTypeCache = getCache("isSubType");
-      final String key = child + "->" + parent;
-      final Boolean cached = isSubTypeCache.get(key);
-      if (cached == null) {
-        final Boolean toCache = isValidSubTypeNoCache(child, parent);
-        isSubTypeCache.put(key, toCache);
-        return toCache;
-      } else {
-        return cached;
-      }
-    } else {
-      return isValidSubTypeNoCache(child, parent);
+    Boolean result = null;
+    final Map<String, Boolean> isSubTypeCache = getCache("isSubType");
+
+    final String key = child + "->" + parent;
+    result = isSubTypeCache.get(key);
+
+    if (result == null) {
+      result = isValidSubTypeNoCache(child, parent);
+      isSubTypeCache.put(key, result);
     }
+
+    return result;
   }
 
-  protected final boolean isValidSubTypeNoCache(final EntityID child, final EntityID parent) {
+  private final boolean isValidSubTypeNoCache(final EntityID child, final EntityID parent) {
     return Objects.equals(child, parent) || execute(new IsSubType(child, parent)).isSubType();
   }
 
-  protected final EntityInterface retrieveValidSparseEntityByName(final String name)
-      throws Message {
-    return retrieveValidSparseEntityById(retrieveValidIDByName(name), null);
+  private final EntityInterface retrieveValidLazyEntityByName(final String name, String version) {
+    EntityID id = null;
+
+    final Map<String, EntityID> cache = getCache("validEntityByName");
+    String key = name;
+    if (version != null && !version.equals("HEAD")) {
+      key += version;
+    }
+
+    id = cache.get(key);
+    if (id == null) {
+      id = retrieveValidIDByName(name, version);
+      cache.put(key, id);
+    }
+
+    return retrieveValidLazyEntityById(id, version);
   }
 
-  protected final EntityInterface retrieveValidSparseEntityById(
-      final EntityID id, final String version) throws Message {
+  private final EntityInterface retrieveValidLazyEntityById(
+      final EntityID id, final String version) {
+    EntityInterface result = null;
 
-    String resulting_version = version;
-    if (version == null || version.equals("HEAD")) {
-      // the targeted entity version is the entity after the transaction or the
-      // entity without a specific version. Thus we have to fetch the entity
-      // from the container if possible.
-      final EntityInterface ret = getEntityById(id);
-      if (ret != null) {
-        return ret;
-      }
-    } else if (version.startsWith("HEAD~")) {
-      final EntityInterface entById = getEntityById(id);
-      if (entById != null && entById.getEntityStatus() != EntityStatus.VALID) {
-        // if version is HEAD~{OFFSET} with {OFFSET} > 0 and the targeted entity is is to be
-        // updated, the actual offset has to be reduced by 1. HEAD always denotes the entity@HEAD
-        // *after* the successful transaction, so that it is consistent with subsequent retrieves.
-        final int offset = Integer.parseInt(version.substring(5)) - 1;
-        if (offset == 0) {
-          // special case HEAD~1
-          resulting_version = "HEAD";
-        } else {
-          resulting_version = new StringBuilder().append("HEAD~").append(offset).toString();
-        }
-      }
+    final Map<String, EntityInterface> cache = getCache("validEntityById");
+    String key = id.toString();
+    if (version != null && !version.equals("HEAD")) {
+      key += version;
     }
 
-    final EntityInterface ret =
-        execute(new RetrieveSparseEntity(id, resulting_version)).getEntity();
-    if (ret.getEntityStatus() == EntityStatus.NONEXISTENT) {
-      throw ServerMessages.ENTITY_DOES_NOT_EXIST;
+    result = cache.get(key);
+    if (result == null) {
+      result = retrieveValidLazyEntityByIdNoCache(id, version);
+      cache.put(key, result);
     }
-    return ret;
-  }
 
-  protected final EntityInterface retrieveValidEntity(final EntityID id) {
-    return execute(new RetrieveFullEntityTransaction(id)).getContainer().get(0);
+    return result;
   }
 
-  protected final EntityID retrieveValidIDByName(final String name) {
-    return execute(new GetIDByName(name)).getId();
+  private final EntityInterface retrieveValidLazyEntityByIdNoCache(
+      final EntityID id, final String version) {
+
+    final EntityInterface ret = execute(new RetrieveSparseEntity(id, version)).getEntity();
+    if (ret.getEntityStatus() == EntityStatus.NONEXISTENT) {
+      throw new EntityDoesNotExistException();
+    }
+    return new LazyEntityResolver(ret, getTransaction());
   }
 
-  protected EntityInterface retrieveParentsOfValidEntity(final EntityInterface entity) {
-    execute(new RetrieveParents(entity));
-    return entity;
+  protected final EntityID retrieveValidIDByName(final String name, String version) {
+    return execute(new GetIDByName(name, version)).getId();
   }
 
   /**
@@ -334,7 +321,7 @@ public abstract class Job {
   private static void scanJobClasspath() {
     if (allClasses == null || loadAlways == null) {
       allClasses = new HashMap<>();
-      loadAlways = new ArrayList<>();
+      loadAlways = new LinkedList<>();
       Reflections jobPackage = new Reflections("org.caosdb.server.jobs.core");
       Set<Class<? extends Job>> allClassesSet = jobPackage.getSubTypesOf(Job.class);
       allClassesSet.addAll(jobPackage.getSubTypesOf(FlagJob.class));
@@ -383,11 +370,11 @@ public abstract class Job {
       final EntityInterface entity,
       final Transaction<? extends TransactionContainer> transaction) {
     if (dt == null) {
-      return new ArrayList<Job>();
+      return new LinkedList<Job>();
     }
     if (dt instanceof ReferenceDatatype2) {
       return jobConfig.getConfiguredJobs(
-          EntityID.DEFAULT_DOMAIN, new EntityID(17), entity, transaction);
+          EntityID.DEFAULT_DOMAIN, new EntityID("17"), entity, transaction);
     } else if (dt instanceof AbstractCollectionDatatype) {
       final AbstractDatatype datatype = ((AbstractCollectionDatatype) dt).getDatatype();
       return loadDataTypeSpecificJobs(datatype, entity, transaction);
@@ -401,18 +388,22 @@ public abstract class Job {
   public List<Job> loadStandardJobs(
       final EntityInterface entity, final Transaction<? extends TransactionContainer> transaction) {
 
-    final ArrayList<Job> jobs = new ArrayList<>();
+    final List<Job> jobs = new LinkedList<>();
     // load permanent jobs
-    for (final Class<? extends Job> j : loadAlways) {
-      if (EntityJob.class.isAssignableFrom(j)
-          && j.getAnnotation(JobAnnotation.class).transaction().isInstance(transaction)) {
-        jobs.add(getJob(j, JobFailureSeverity.ERROR, entity, transaction));
+    for (final Class<? extends Job> jobClass : loadAlways) {
+      if (EntityJob.class.isAssignableFrom(jobClass)
+          && jobClass.getAnnotation(JobAnnotation.class).transaction().isInstance(transaction)) {
+        Job j = getJob(jobClass, JobFailureSeverity.ERROR, entity, transaction);
+        if (j != null) {
+          jobs.add(j);
+        }
       }
     }
 
     // load general rules
     final List<Job> generalRules =
-        jobConfig.getConfiguredJobs(EntityID.DEFAULT_DOMAIN, new EntityID(0), entity, transaction);
+        jobConfig.getConfiguredJobs(
+            EntityID.DEFAULT_DOMAIN, new EntityID("0"), entity, transaction);
     if (generalRules != null) {
       jobs.addAll(generalRules);
     }
@@ -541,10 +532,6 @@ public abstract class Job {
         + "]";
   }
 
-  public void print() {
-    System.out.println(toString());
-  }
-
   public TransactionStage getTransactionStage() {
     return this.stage;
   }
@@ -559,33 +546,80 @@ public abstract class Job {
    */
   protected EntityInterface resolve(final EntityInterface entity)
       throws EntityWasNotUniqueException {
-    EntityInterface resolvedEntity = null;
-    if (!entity.hasId() && entity.hasName()) {
-      resolvedEntity = getEntityByName(entity.getName());
+    return resolve(entity.getId(), entity.getName(), entity.getVersion());
+  }
+
+  protected EntityInterface resolve(EntityID id) {
+    return resolve(id, null, (String) null);
+  }
+
+  protected EntityInterface resolve(EntityID id, String name, String versionId)
+      throws EntityDoesNotExistException, EntityWasNotUniqueException {
+    EntityInterface resolvedEntity = getEntityById(id);
+
+    String resulting_version = versionId;
+    if (versionId == null || versionId.equals("HEAD")) {
+      resulting_version = null;
+      versionId = null;
+    } else if (versionId.startsWith("HEAD~")) {
       if (resolvedEntity == null) {
-        final EntityID eid = retrieveValidIDByName(entity.getName());
-        entity.setId(eid);
+        resolvedEntity = getEntityByName(name);
+      }
+      if (resolvedEntity != null && resolvedEntity.getEntityStatus() == EntityStatus.QUALIFIED) {
+        // if versionId is HEAD~{OFFSET} with {OFFSET} > 0 and the targeted entity is is to be
+        // updated, the actual offset has to be reduced by 1. HEAD always denotes the entity@HEAD
+        // *after* the successful transaction, so that it is consistent with subsequent retrieves.
+        final int offset = Integer.parseInt(versionId.substring(5)) - 1;
+        if (offset == 0) {
+          // special case HEAD~1
+          resulting_version = "HEAD";
+        } else {
+          resulting_version = new StringBuilder().append("HEAD~").append(offset).toString();
+        }
       }
+      resolvedEntity = null;
+    } else {
+      // We want another version, throw away current result.
+      resolvedEntity = null;
     }
 
-    if (entity.hasId()) {
-      // get entity from container
-      resolvedEntity = getEntityById(entity.getId());
-      if (resolvedEntity == null && !entity.getId().isTemporary()) {
-        resolvedEntity = retrieveValidEntity(entity.getId());
+    if (resolvedEntity == null && id != null) {
+      try {
+        resolvedEntity = retrieveValidLazyEntityById(id, resulting_version);
+      } catch (EntityDoesNotExistException e) {
+        // ignore here, try to find by name.
       }
     }
 
+    // Last resort: find by name ...
+    if (resolvedEntity == null && versionId == null) {
+      // ... from current transaction's container
+      resolvedEntity = getEntityByName(name);
+    }
+
+    if (resolvedEntity == null && name != null) {
+      // ... from database
+      resolvedEntity = retrieveValidLazyEntityByName(name, resulting_version);
+    }
+
+    if (resolvedEntity == null) {
+      throw new EntityDoesNotExistException();
+    }
     return resolvedEntity;
   }
 
+  protected EntityInterface resolve(EntityID id, String name, Version version) {
+    String versionId = version != null ? version.getId() : null;
+    return resolve(id, name, versionId);
+  }
+
   /**
    * Return those matching jobs which are annotated with the "loadAlways" attribute.
    *
    * @return A list with the jobs.
    */
   public static List<Job> loadPermanentContainerJobs(final Transaction<?> transaction) {
-    final ArrayList<Job> jobs = new ArrayList<>();
+    final List<Job> jobs = new LinkedList<>();
     // load permanent jobs: ContainerJob classes with the correct transaction
     for (final Class<? extends Job> j : loadAlways) {
       if (ContainerJob.class.isAssignableFrom(j)
@@ -595,4 +629,22 @@ public abstract class Job {
     }
     return jobs;
   }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj != null && obj instanceof Job) {
+      Job other = (Job) obj;
+      return other.getClass().equals(this.getClass())
+          && Objects.equals(other.getEntity(), this.getEntity())
+          && other.getFailureSeverity().equals(this.getFailureSeverity());
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return getClass().hashCode()
+        + (getEntity() == null ? 0 : getEntity().hashCode())
+        + getFailureSeverity().hashCode();
+  }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/JobConfig.java b/src/main/java/org/caosdb/server/jobs/JobConfig.java
index 40917b36714ee95ef491a266580068a06f51703a..b2bb0d4a1b13a98dd68893c9f0cad7bc8192edba 100644
--- a/src/main/java/org/caosdb/server/jobs/JobConfig.java
+++ b/src/main/java/org/caosdb/server/jobs/JobConfig.java
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -141,8 +141,8 @@ public class JobConfig {
           "Could not parse the job rules. Lines of five comma-separated values expected");
     }
     try {
-      final Integer domain = Integer.parseInt(row[0]);
-      final Integer entity = Integer.parseInt(row[1]);
+      final String domain = row[0];
+      final String entity = row[1];
       final String transaction = row[2];
       final String job = row[3];
       final JobFailureSeverity severity = JobFailureSeverity.valueOf(row[4]);
@@ -158,7 +158,7 @@ public class JobConfig {
   }
 
   /**
-   * Factory method for the instanciation and configuration of jobs for a specific entity.
+   * Factory method for the instantiation and configuration of jobs for a specific entity.
    *
    * @param domain the domain of the rule
    * @param entity the entity of the rule (this might be a particular datatype or a role, like
@@ -184,9 +184,13 @@ public class JobConfig {
       final List<Job> result = new LinkedList<>();
       jobRules.forEach(
           config -> {
-            result.add(
-                Job.getJob(
-                    (String) config[0], (JobFailureSeverity) config[1], target, transaction));
+            Job j =
+                Job.getJob((String) config[0], (JobFailureSeverity) config[1], target, transaction);
+            if (j == null) {
+              throw new NullPointerException("Could not load job: " + config[0]);
+            } else {
+              result.add(j);
+            }
           });
       return result;
     }
diff --git a/src/main/java/org/caosdb/server/jobs/LazyEntityResolver.java b/src/main/java/org/caosdb/server/jobs/LazyEntityResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..7088ce7d35903daf34a0e060241aa22d749988c0
--- /dev/null
+++ b/src/main/java/org/caosdb/server/jobs/LazyEntityResolver.java
@@ -0,0 +1,101 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.jobs;
+
+import org.caosdb.server.database.backend.transaction.RetrieveParents;
+import org.caosdb.server.database.backend.transaction.RetrieveProperties;
+import org.caosdb.server.entity.EntityInterface;
+import org.caosdb.server.entity.container.ParentContainer;
+import org.caosdb.server.entity.container.PropertyContainer;
+import org.caosdb.server.entity.wrapper.EntityWrapper;
+import org.caosdb.server.transaction.Transaction;
+
+/**
+ * Implementation of {@link EntityInterface} which retrieves the parents and properties only when
+ * requested via getProperties and getParents.
+ *
+ * <p>This is particularly useful for jobs sharing the same entity object between jobs which need
+ * different parts of it while reducing the logic of checking whether the entity is "only" sparse,
+ * or has been retrieved fully and so on.
+ *
+ * <p>However, when the entities parents or properties are being retrieved after the transaction's
+ * access has been released, an {@link IllegalStateException} will be thrown.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class LazyEntityResolver extends EntityWrapper {
+
+  private Transaction<?> transaction;
+  private boolean propertiesResolved = false;
+  private boolean parentsResolved = false;
+
+  /**
+   * Constructor.
+   *
+   * <p>Initialize this with a sparse entity.
+   */
+  public LazyEntityResolver(EntityInterface entity, Transaction<?> transaction) {
+    super(entity);
+    this.transaction = transaction;
+  }
+
+  public void resolveParents() {
+    if (parentsResolved) return;
+    parentsResolved = true;
+    transaction.execute(new RetrieveParents(getWrapped()), transaction.getAccess());
+  }
+
+  private void resolveProperties() {
+    if (propertiesResolved) return;
+    propertiesResolved = true;
+    transaction.execute(new RetrieveProperties(getWrapped()), transaction.getAccess());
+  }
+
+  public void resolveAll() {
+    resolveParents();
+    resolveProperties();
+    // release the transaction for the garbage collector
+    this.transaction = null;
+  }
+
+  @Override
+  public ParentContainer getParents() {
+    resolveParents();
+    return super.getParents();
+  }
+
+  @Override
+  public boolean hasParents() {
+    resolveParents();
+    return super.hasParents();
+  }
+
+  @Override
+  public PropertyContainer getProperties() {
+    resolveProperties();
+    return super.getProperties();
+  }
+
+  @Override
+  public boolean hasProperties() {
+    resolveProperties();
+    return super.hasProperties();
+  }
+}
diff --git a/src/main/java/org/caosdb/server/jobs/Schedule.java b/src/main/java/org/caosdb/server/jobs/Schedule.java
index 57474da515418745ed0457962596dfce233bff48..1b7ac8f4b41118803e7d5a540be6a1a3ba57cfec 100644
--- a/src/main/java/org/caosdb/server/jobs/Schedule.java
+++ b/src/main/java/org/caosdb/server/jobs/Schedule.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020-2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020-2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -35,6 +35,8 @@ import org.caosdb.server.entity.EntityInterface;
  * <p>The Schedule class orders jobs by {@link TransactionStage} and also assures that jobs are
  * skipped when appropriate and to prevent that jobs run more than once (because sometimes they
  * trigger each other).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class Schedule {
 
@@ -44,20 +46,26 @@ public class Schedule {
   public List<ScheduledJob> addAll(final Collection<Job> jobs) {
     final List<ScheduledJob> result = new ArrayList<ScheduledJob>(jobs.size());
     for (final Job j : jobs) {
-      result.add(add(j));
+      ScheduledJob scheduledJob = add(j);
+      if (scheduledJob != null) {
+        result.add(scheduledJob);
+      }
     }
     return result;
   }
 
   public ScheduledJob add(final Job j) {
-    final ScheduledJob ret = new ScheduledJob(j);
-    List<ScheduledJob> jobs = jobLists.get(ret.getTransactionStage().ordinal());
+    final ScheduledJob scheduled = new ScheduledJob(j);
+    List<ScheduledJob> jobs = jobLists.get(scheduled.getTransactionStage().ordinal());
     if (jobs == null) {
       jobs = new CopyOnWriteArrayList<ScheduledJob>();
-      jobLists.put(ret.getTransactionStage().ordinal(), jobs);
+      jobLists.put(scheduled.getTransactionStage().ordinal(), jobs);
+    }
+    if (!jobs.contains(scheduled)) {
+      jobs.add(scheduled);
+      return scheduled;
     }
-    jobs.add(ret);
-    return ret;
+    return null;
   }
 
   /** Run all Jobs from the specified {@link TransactionStage}. */
@@ -71,7 +79,7 @@ public class Schedule {
   }
 
   public void runJob(final ScheduledJob scheduledJob) {
-    if (scheduledJob.skip()) {
+    if (scheduledJob == null || scheduledJob.skip()) {
       return;
     }
     final ScheduledJob parent = this.running;
diff --git a/src/main/java/org/caosdb/server/jobs/ScheduledJob.java b/src/main/java/org/caosdb/server/jobs/ScheduledJob.java
index 2122b34de5f0b60db4c2b6d4c1c2358d3df02851..1754f19f5fdab5b32e19fcba7758481f0dba8948 100644
--- a/src/main/java/org/caosdb/server/jobs/ScheduledJob.java
+++ b/src/main/java/org/caosdb/server/jobs/ScheduledJob.java
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -28,7 +28,7 @@ import org.caosdb.server.entity.Message;
  * <p>It is mainly a means to have simplified interface for the Scheduler which also measures the
  * execution time of the job "from outside".
  *
- * @author Timm Fitschen (t.fitschen@indiscale.com)
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class ScheduledJob {
 
@@ -102,4 +102,18 @@ public class ScheduledJob {
   public Job getJob() {
     return job;
   }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof ScheduledJob) {
+      ScheduledJob other = (ScheduledJob) obj;
+      return this.job.equals(other.job);
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return job.hashCode();
+  }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckChildDependencyExistent.java b/src/main/java/org/caosdb/server/jobs/core/CheckChildDependencyExistent.java
deleted file mode 100644
index d60db5a3ea2f58caefe240894920318e01efc8a6..0000000000000000000000000000000000000000
--- a/src/main/java/org/caosdb/server/jobs/core/CheckChildDependencyExistent.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-package org.caosdb.server.jobs.core;
-
-import java.util.List;
-import java.util.Objects;
-import org.caosdb.server.database.backend.transaction.GetChildren;
-import org.caosdb.server.entity.EntityID;
-import org.caosdb.server.entity.EntityInterface;
-import org.caosdb.server.jobs.EntityJob;
-import org.caosdb.server.utils.EntityStatus;
-import org.caosdb.server.utils.ServerMessages;
-
-/**
- * Check whether any children of this entity do exist. There must not be any children left when an
- * entity is to be deleted. If all children are to be deleted, too, the test passes.
- *
- * @author tf
- */
-public class CheckChildDependencyExistent extends EntityJob {
-
-  @Override
-  public final void run() {
-    if (getEntity().getDomain() == null
-        || Objects.equals(getEntity().getDomain(), EntityID.DEFAULT_DOMAIN)) {
-
-      final List<EntityID> children = execute(new GetChildren(getEntity().getId())).getList();
-
-      // loop:
-      for (final EntityID id : children) {
-        final EntityInterface foreign = getEntityById(id);
-        if (foreign == null) {
-          // if the child is not in the container, the test fails.
-          getEntity().addError(ServerMessages.REQUIRED_BY_PERSISTENT_ENTITY);
-          getEntity().addInfo("Required by entity " + id + ".");
-          getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-        }
-
-        // // loop through all entities in the current container
-        // for (final EntityInterface e : getContainer()) {
-        //
-        // // if e is a child
-        // if (e.getId().equals(id)) {
-        // if (e.getEntityStatus() == EntityStatus.UNQUALIFIED) {
-        // getEntity().addError(ServerMessages.REQUIRED_BY_UNQUALIFIED);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-        // } else {
-        // // if the children are among the entities in the
-        // // container which is to be deleted, the test passes
-        // e.acceptObserver(new Observer() {
-        // @Override
-        // public boolean notifyObserver(final String evt,
-        // final Observable o) {
-        // if (evt == Entity.ENTITY_STATUS_CHANGED_EVENT && o == e) {
-        // if (e.getEntityStatus() == EntityStatus.UNQUALIFIED) {
-        // getEntity().addError(
-        // ServerMessages.REQUIRED_BY_UNQUALIFIED);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-        // return false;
-        // }
-        // }
-        // return true;
-        // }
-        // });
-        // }
-        // continue loop;
-        // }
-        // }
-
-        // // if the child is not in the container, the test fails.
-        // getEntity().addError(ServerMessages.REQUIRED_BY_PERSISTENT_ENTITY);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-      }
-    }
-  }
-}
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java b/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
index 40e01d2636509774555f1514c75bb0bf16870539..b3a06ca09d7870da843a2f3ad295e019ab683c12 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -41,10 +40,11 @@ import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
 /**
- * Check whether the entity has a data type. Assign the data type of the abstract property if
- * necessary
+ * Check whether the entity has a data type.
+ *
+ * <p>Assign the data type of the abstract property if necessary.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public final class CheckDatatypePresent extends EntityJob {
 
@@ -115,44 +115,15 @@ public final class CheckDatatypePresent extends EntityJob {
   }
 
   private void checkReference2(final ReferenceDatatype2 datatype) throws Message {
+    EntityInterface datatypeEntity = resolve(datatype.getId(), datatype.getName(), (String) null);
 
-    if (datatype.getId() == null) {
-      // try and get from container...
-      final EntityInterface datatypeEntity = getEntityByName(datatype.getName());
-
-      // if the container carried a corresponding entity
-      if (datatypeEntity != null) {
-        assertAllowedToUse(datatypeEntity);
-
-        // ... we set it as the datatypevalue
-        datatype.setEntity(datatypeEntity);
-      } else {
-
-        // else try and get from database.
-        final EntityInterface validDatatypeEntity =
-            retrieveValidSparseEntityByName(datatype.getName());
-        assertAllowedToUse(validDatatypeEntity);
-        datatype.setId(validDatatypeEntity.getId());
-      }
-    } else if (datatype.getId().isTemporary()) {
-      final EntityInterface datatypeEntity = getEntityById(datatype.getId());
-
-      // if the container carried a corresponding entity
-      if (datatypeEntity != null) {
-        assertAllowedToUse(datatypeEntity);
-        // ... we set it as the datatype
-        datatype.setEntity(datatypeEntity);
-      } else {
-
-        throw ServerMessages.UNKNOWN_DATATYPE;
-      }
-    } else {
-
-      final EntityInterface validDatatypeEntity =
-          retrieveValidSparseEntityById(datatype.getId(), null);
-      assertAllowedToUse(validDatatypeEntity);
-      datatype.setEntity(validDatatypeEntity);
+    if (datatypeEntity == null) {
+      throw ServerMessages.UNKNOWN_DATATYPE;
     }
+
+    // do the actual checking
+    assertAllowedToUse(datatypeEntity);
+    datatype.setEntity(datatypeEntity);
   }
 
   private void assertAllowedToUse(final EntityInterface datatype) {
@@ -160,62 +131,39 @@ public final class CheckDatatypePresent extends EntityJob {
   }
 
   private void checkIfOverride() throws Message {
-    if (getEntity().hasId() && !getEntity().getId().isTemporary()) {
-      // get data type from database
-      final EntityInterface foreign = retrieveValidSparseEntityById(getEntity().getId(), null);
-
-      if (foreign.hasDatatype() && !foreign.getDatatype().equals(getEntity().getDatatype())) {
-        // is override!
-        getEntity().setDatatypeOverride(true);
-      }
-    } else {
-      // get data type from container
-      EntityInterface abstractProperty = null;
-      if (getEntity().hasId()) {
-        abstractProperty = getEntityById(getEntity().getId());
-      } else if (getEntity().hasName()) {
-        abstractProperty = getEntityByName(getEntity().getName());
-      }
-      if (abstractProperty != null && abstractProperty.hasDatatype()) {
-        if (!getEntity().getDatatype().equals(abstractProperty.getDatatype())) {
-          // is override!
-          getEntity().setDatatypeOverride(true);
-        }
-      }
+    EntityInterface abstractProperty = resolve(getEntity());
+    if (abstractProperty != null
+        && abstractProperty.hasDatatype()
+        && !abstractProperty.getDatatype().equals(getEntity().getDatatype())) {
+      // is override!
+      getEntity().setDatatypeOverride(true);
     }
   }
 
+  /**
+   * If this is a record type property or a concrete property, assign the data type of the
+   * corresponding abstract property.
+   */
   private void inheritDatatypeFromAbstractEntity() throws Message {
-    // if this is a record type property or a concrete property, assign
-    // the data type of the corresponding abstract property.
-    if (getEntity().hasId() && !getEntity().getId().isTemporary()) {
-      // get from data base
-      final EntityInterface foreign = retrieveValidSparseEntityById(getEntity().getId(), null);
-      inheritDatatypeFromForeignEntity(foreign);
-    } else if (getEntity().hasId() && getEntity().getId().isTemporary()) {
-      // get from container
-      final EntityInterface foreign = getEntityById(getEntity().getId());
-      inheritDatatypeFromForeignEntity(foreign);
-    }
-  }
-
-  private void inheritDatatypeFromForeignEntity(final EntityInterface foreign) {
-    if (foreign != null && foreign.hasDatatype()) {
-      getEntity().setDatatype(foreign.getDatatype());
-    } else if (foreign != null && foreign != getEntity() && foreign.getRole() == Role.RecordType) {
-      getEntity().setDatatype(ReferenceDatatype2.datatypeFactory(foreign.getId()));
+    EntityInterface abstractProperty = resolve(getEntity());
+    if (abstractProperty != null && abstractProperty.hasDatatype()) {
+      getEntity().setDatatype(abstractProperty.getDatatype());
+    } else if (abstractProperty != null
+        && abstractProperty != getEntity()
+        && abstractProperty.getRole() == Role.RecordType) {
+      getEntity().setDatatype(ReferenceDatatype2.datatypeFactory(abstractProperty.getId()));
     }
   }
 
   private void resolveId(final EntityInterface entity) {
     if (!entity.hasId() && entity.hasName()) {
       try {
-        entity.setId(retrieveValidIDByName(entity.getName()));
-        if (entity.getEntityStatus() != EntityStatus.UNQUALIFIED) {
-          entity.setEntityStatus(EntityStatus.VALID);
+        EntityInterface resolved = resolve(entity);
+        if (resolved == null) {
+          entity.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
+        } else {
+          entity.setId(resolved.getId());
         }
-      } catch (final EntityDoesNotExistException exc) {
-        entity.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
       } catch (final EntityWasNotUniqueException exc) {
         entity.addError(ServerMessages.ENTITY_NAME_DUPLICATES);
       }
@@ -227,14 +175,12 @@ public final class CheckDatatypePresent extends EntityJob {
 
     AbstractDatatype datatype = null;
     for (final EntityInterface parent : getEntity().getParents()) {
-      EntityInterface parentEntity = null;
-      if (!parent.getId().isTemporary()) {
-        parentEntity = retrieveValidSparseEntityById(parent.getId(), null);
-      } else {
-        parentEntity = getEntityById(parent.getId());
+      EntityInterface parentEntity = resolve(parent);
+      if (!parentEntity.hasDatatype() && parentEntity.getEntityStatus() == EntityStatus.QUALIFIED) {
         runJobFromSchedule(parentEntity, CheckDatatypePresent.class);
       }
-      if (parentEntity.hasDatatype()) {
+      if (parentEntity.hasDatatype()
+          && parentEntity.getEntityStatus() != EntityStatus.UNQUALIFIED) {
         if (datatype != null && !parentEntity.getDatatype().equals(datatype)) {
           getEntity().addError(ServerMessages.DATATYPE_INHERITANCE_AMBIGUOUS);
           return;
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckReferenceDependencyExistent.java b/src/main/java/org/caosdb/server/jobs/core/CheckDependenciesBeforeDeletion.java
similarity index 53%
rename from src/main/java/org/caosdb/server/jobs/core/CheckReferenceDependencyExistent.java
rename to src/main/java/org/caosdb/server/jobs/core/CheckDependenciesBeforeDeletion.java
index 2edbc5a270db93312c73b8c960c615a161e8907b..ecbbf4af7fb4a81605d61a3d251b88c4f1d0917a 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckReferenceDependencyExistent.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckDependenciesBeforeDeletion.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -32,13 +31,13 @@ import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
 /**
- * Check whether an entity is referenced by other entities. In the event that someone wants to
- * delete this entity, this entity must not be referenced by any other entity which is not deleted
- * along with this entity.
+ * Check whether an entity is referenced by other entities, is being used as a data type by other
+ * entities or has direct children which are not to be deleted along with this entity and add an
+ * appropriate error if so.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
-public class CheckReferenceDependencyExistent extends EntityJob {
+public class CheckDependenciesBeforeDeletion extends EntityJob {
   @Override
   public final void run() {
     if (getEntity().getDomain() == null
@@ -59,42 +58,6 @@ public class CheckReferenceDependencyExistent extends EntityJob {
           getEntity().addInfo("Required by entity " + id + ".");
           getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
         }
-        // for (final EntityInterface e : getContainer()) {
-        // if (e.getId().equals(id)) {
-        // // entity is in the container.
-        // if (e.getEntityStatus() == EntityStatus.UNQUALIFIED) {
-        // getEntity().addError(ServerMessages.REQUIRED_BY_UNQUALIFIED);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-        // } else {
-        // e.acceptObserver(new Observer() {
-        // @Override
-        // public boolean notifyObserver(final String evt,
-        // final Observable o) {
-        // if (e == o && evt == Entity.ENTITY_STATUS_CHANGED_EVENT) {
-        // if (e.getEntityStatus() == EntityStatus.UNQUALIFIED) {
-        // getEntity().addError(
-        // ServerMessages.REQUIRED_BY_UNQUALIFIED);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
-        // return false;
-        // }
-        // }
-        // return true;
-        // }
-        // });
-        // }
-        //
-        // continue loop;
-        // }
-        // }
-
-        // // dependent entity is not in the container. That is, it will
-        // // not be deleted. Therefore, this entity cannot be deleted
-        // // either.
-        // getEntity().addError(ServerMessages.REQUIRED_BY_PERSISTENT_ENTITY);
-        // getEntity().addInfo("Required by entity " + id + ".");
-        // getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
       }
     }
   }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckParOblPropPresent.java b/src/main/java/org/caosdb/server/jobs/core/CheckParOblPropPresent.java
index e6ba9da430e6218e5c40fba968c309ed94152bf6..eba79831468b1f6799507ca0866a64e594997caa 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckParOblPropPresent.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckParOblPropPresent.java
@@ -93,7 +93,7 @@ public class CheckParOblPropPresent extends EntityJob {
           // loop over all properties of the entity
           for (final EntityInterface entityProperty : getEntity().getProperties()) {
 
-            if (isSubType(entityProperty, parentProperty)) {
+            if (isSubType(resolve(entityProperty), parentProperty)) {
               // continue outer loop means that we
               // found an entityProperty that
               // implements the obligatory
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 8895ae9adb4d12da2f7789a8798ca0fb9d183c05..fd235c21319d7b573db1cd42b23d9184aa7e56e6 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -42,7 +41,7 @@ import org.caosdb.server.utils.ServerMessages;
 /**
  * Check whether all parents of an entity are valid/qualified.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 @JobAnnotation(stage = TransactionStage.PRE_CHECK)
 public class CheckParValid extends EntityJob {
@@ -60,73 +59,21 @@ public class CheckParValid extends EntityJob {
           if (!parent.hasId() && !parent.hasName()) {
             // The parent has neither an id nor a name.
             // Therefore it cannot be identified.
-
-            throw ServerMessages.ENTITY_HAS_NO_NAME_OR_ID;
-          }
-
-          if (parent.hasId()) {
-            // check parent by id
-            if (!parent.getId().isTemporary()) {
-              // id isn't temporary, i.e., parent is already in the database and
-              // can be retrieved by id
-              final EntityInterface foreign = retrieveValidSparseEntityById(parent.getId(), null);
-              // check permissions for this
-              // parentforeign.acceptObserver(o)
-              assertAllowedToUse(foreign);
-              parent.setAffiliation(getAffiliation(getEntity().getRole(), foreign.getRole()));
-              continue;
-            } else {
-              // id < 0 (parent is to be stored along with
-              // this entity)
-
-              // get entity with corresponding (negative) id
-              // from container
-              final EntityInterface foreign = getEntityById(parent.getId());
-
-              // if the container carried a corresponding
-              // entity
-              if (foreign != null) {
-                assertAllowedToUse(foreign);
-
-                parent.setAffiliation(getAffiliation(getEntity().getRole(), foreign.getRole()));
-
-                // ... we can set it as the parent
-                parent.linkIdToEntity(foreign);
-                continue;
-              }
-            }
+            parent.addError(ServerMessages.ENTITY_HAS_NO_NAME_OR_ID);
           }
-
-          // parent doesn't have an id.
-          if (parent.hasName()) {
-            if (getEntityByName(parent.getName()) != null) {
-              // get the parent entity from the container by its
-              // name
-              final EntityInterface foreign = getEntityByName(parent.getName());
-
-              assertAllowedToUse(foreign);
-              parent.setAffiliation(getAffiliation(getEntity().getRole(), foreign.getRole()));
-              parent.linkIdToEntity(foreign);
-              continue;
-            } else {
-              // check parent by name (parent is expected to be
-              // valid). This only works if the name is unique.
-              final EntityInterface foreign = retrieveValidSparseEntityByName(parent.getName());
-              assertAllowedToUse(foreign);
-              parent.setAffiliation(getAffiliation(getEntity().getRole(), foreign.getRole()));
-              parent.setId(foreign.getId());
-              continue;
-            }
+          try {
+            EntityInterface foreign = resolve(parent.getId(), parent.getName(), (String) null);
+            assertAllowedToUse(foreign);
+            parent.linkIdToEntity(foreign);
+            parent.setAffiliation(getAffiliation(getEntity().getRole(), foreign.getRole()));
+          } catch (EntityDoesNotExistException e) {
+            parent.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
           }
-
-          parent.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
         } catch (final Message m) {
           parent.addError(m);
         } catch (AuthorizationException e) {
           parent.addError(ServerMessages.AUTHORIZATION_ERROR);
           parent.addInfo(e.getMessage());
-        } catch (final EntityDoesNotExistException exc) {
-          parent.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
         } catch (final EntityWasNotUniqueException exc) {
           parent.addError(ServerMessages.ENTITY_NAME_DUPLICATES);
         }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
index 23a92340f5befbfbe7ded2fe95d3244b5ff78594..bfd2bc3019d1d4ae6204ebbe5b5975932603ed76 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -41,7 +40,7 @@ import org.caosdb.server.utils.ServerMessages;
 /**
  * Check whether all properties of an entity are valid or qualified.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 @JobAnnotation(stage = TransactionStage.PRE_CHECK)
 public class CheckPropValid extends EntityJob {
@@ -54,75 +53,21 @@ public class CheckPropValid extends EntityJob {
         if (property.getEntityStatus() == EntityStatus.QUALIFIED) {
           // this property is to be tested.
 
-          // does this property have an id at all?
-          if (property.hasId()) {
-            if (!property.getId().isTemporary()) {
-
-              final EntityInterface abstractProperty =
-                  retrieveValidSparseEntityById(property.getId(), null);
-
-              assertAllowedToUse(abstractProperty);
-
-              deriveOverrideStatus(property, abstractProperty);
-              continue;
-            } else {
-              // task here: find the corresponding abstract
-              // property (or rarely any other entity) in this
-              // container which has the same (negative) id.
-
-              // fetch the abstractProperty from the container.
-              final EntityInterface abstractProperty = getEntityById(property.getId());
-
-              if (abstractProperty != null) {
-                assertAllowedToUse(abstractProperty);
-
-                // link the id of the property to the id of
-                // the abstractProperty means. This has the
-                // effect that the property will have a
-                // valid id as soon as the abstractProperty
-                // has been inserted.
-                property.linkIdToEntity(abstractProperty);
-                deriveOverrideStatus(property, abstractProperty);
-                continue;
-              } else if (!property.hasName()) {
-                // an abstractProperty with this (negative) id
-                // had not been found in this container.
-                throw ENTITY_DOES_NOT_EXIST;
-              }
-            }
-          }
-
-          if (property.hasName()) {
-
-            // try and get it from the container
-            EntityInterface foreign = getEntityByName(property.getName());
-            if (foreign != null) {
-              assertAllowedToUse(foreign);
-
-              // link the id of the property to the id of
-              // the abstractProperty means. This has the
-              // effect that the property will have a
-              // valid id as soon as the abstractProperty
-              // has been inserted.
-              property.linkIdToEntity(foreign);
-              deriveOverrideStatus(property, foreign);
-            } else {
-              foreign = retrieveValidSparseEntityByName(property.getName());
-
-              assertAllowedToUse(foreign);
-
-              property.setId(foreign.getId());
-
-              deriveOverrideStatus(property, foreign);
-            }
-          }
-
           if (!property.hasName() && !property.hasId()) {
             // The property has neither an id nor a name.
             // Thus it cannot be identified.
 
             throw ServerMessages.ENTITY_HAS_NO_NAME_OR_ID;
           }
+          EntityInterface abstractProperty =
+              resolve(property.getId(), property.getName(), (String) null);
+          if (abstractProperty == null) {
+            property.addError(ENTITY_DOES_NOT_EXIST);
+            continue;
+          }
+          assertAllowedToUse(abstractProperty);
+          deriveOverrideStatus(property, abstractProperty);
+          property.linkIdToEntity(abstractProperty);
         }
       } catch (final Message m) {
         property.addError(m);
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckRefidIsaParRefid.java b/src/main/java/org/caosdb/server/jobs/core/CheckRefidIsaParRefid.java
index 0b8ba45b1cae19812641ed733be7aacc2fb78575..7b0a9977680c378db98dca4d3e7ee31dba06e840 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckRefidIsaParRefid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckRefidIsaParRefid.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -41,10 +40,11 @@ import org.caosdb.server.utils.Observer;
 import org.caosdb.server.utils.ServerMessages;
 
 /**
- * Check if the referenced entity is in the scope of the data type. E.g. if the data type is
- * 'Person' the referenced entity is to be a child of 'Person'.
+ * Check if the referenced entity is in the scope of the data type.
+ *
+ * <p>E.g. if the data type is 'Person' the referenced entity is to be a child of 'Person'.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class CheckRefidIsaParRefid extends EntityJob implements Observer {
 
@@ -82,24 +82,8 @@ public class CheckRefidIsaParRefid extends EntityJob implements Observer {
           for (final IndexedSingleValue v : vals) {
             if (v != null && v.getWrapped() != null) {
               final ReferenceValue rv = (ReferenceValue) v.getWrapped();
-              if (rv.getEntity() != null
-                  && rv.getEntity().hasRole()
-                  && rv.getEntity().getRole() == Role.File) {
-              } else if (rv.getId() != null
-                  && rv.getId().isTemporary()
-                  && getEntityById(rv.getId()) != null
-                  && getEntityById(rv.getId()).getRole() == Role.File) {
-              } else if (rv.getId() == null
-                  && rv.getName() != null
-                  && getEntityByName(rv.getName()) != null
-                  && getEntityByName(rv.getName()).getRole() == Role.File) {
-              } else if (rv.getId() != null
-                  && !rv.getId().isTemporary()
-                  && retrieveValidSparseEntityById(rv.getId(), rv.getVersion()).getRole()
-                      == Role.File) {
-              } else if (rv.getName() != null
-                  && retrieveValidSparseEntityByName(rv.getName()).getRole() == Role.File) {
-              } else {
+              EntityInterface referencedEntity = resolve(rv.getId(), rv.getName(), rv.getVersion());
+              if (referencedEntity.getRole() != Role.File) {
                 throw ServerMessages.REFERENCE_IS_NOT_ALLOWED_BY_DATATYPE;
               }
             }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
index 12b545b8e6fd608e20851d37f34e809acfcd1544..86e95542aaa0e6f373521149d9f7376f09d3972c 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  *   Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020-2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020-2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -43,7 +40,7 @@ import org.caosdb.server.utils.ServerMessages;
 /**
  * Check whether a reference property is pointing to a valid entity.
  *
- * @author tf
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class CheckRefidValid extends EntityJob implements Observer {
   @Override
@@ -83,61 +80,12 @@ public class CheckRefidValid extends EntityJob implements Observer {
   }
 
   private void checkRefValue(final ReferenceValue ref) throws Message {
-    if (ref.getId() != null) {
-      if (!ref.getId().isTemporary()) {
-        final EntityInterface referencedValidEntity =
-            retrieveValidSparseEntityById(ref.getId(), ref.getVersion());
-        assertAllowedToUse(referencedValidEntity);
-
-        // link the entity as versioned entity iff the reference specified a version
-        ref.setEntity(referencedValidEntity, ref.getVersion() != null);
-
-      } else {
-
-        // is the referenced entity yet linked to this refid
-        // property?
-        if (ref.getEntity() == null) {
-
-          // link the entity with the corresponding
-          // negative id to this reference object
-          final EntityInterface referencedEntity = getEntityById(ref.getId());
-          if (referencedEntity != null) {
-            assertAllowedToUse(referencedEntity);
-
-            // link the entity as versioned entity iff the reference specified a version
-            ref.setEntity(referencedEntity, ref.getVersion() != null);
-          } else {
-            throw ServerMessages.REFERENCED_ENTITY_DOES_NOT_EXIST;
-          }
-        }
-        ref.getEntity().acceptObserver(this);
-        checkRefEntity(ref);
-      }
-    } else if (ref.getName() != null) {
-      // is the referenced entity yet linked to this
-      // refid property?
-      if (ref.getEntity() == null) {
-        // the entity is in this container?
-        final EntityInterface referencedEntity = getEntityByName(ref.getName());
-
-        if (referencedEntity != null) {
-          assertAllowedToUse(referencedEntity);
-
-          // link the entity as versioned entity iff the reference specified a version
-          ref.setEntity(referencedEntity, ref.getVersion() != null);
-          if (checkRefEntity(ref)) {
-            ref.getEntity().acceptObserver(this);
-          }
-        } else {
-          final EntityInterface referencedValidEntity =
-              retrieveValidSparseEntityByName(ref.getName());
-          assertAllowedToUse(referencedValidEntity);
-
-          // link the entity as versioned entity iff the reference specified a version
-          ref.setEntity(referencedValidEntity, ref.getVersion() != null);
-        }
-      }
+    EntityInterface referencedEntity = resolve(ref.getId(), ref.getName(), ref.getVersion());
+    if (referencedEntity == null) {
+      throw ServerMessages.REFERENCED_ENTITY_DOES_NOT_EXIST;
     }
+    assertAllowedToUse(referencedEntity);
+    ref.setEntity(referencedEntity, ref.getVersion() != null);
   }
 
   private void assertAllowedToUse(final EntityInterface referencedEntity) {
diff --git a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
index a4c50f8893935d7bbd6091b970b32a8811a08d93..01b0ecb2274a85635dee3fe88f041e50178936fe 100644
--- a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
+++ b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -53,6 +53,7 @@ import org.caosdb.server.entity.container.TransactionContainer;
 import org.caosdb.server.entity.wrapper.Property;
 import org.caosdb.server.entity.xml.ToElementable;
 import org.caosdb.server.jobs.EntityJob;
+import org.caosdb.server.jobs.LazyEntityResolver;
 import org.caosdb.server.permissions.EntityACI;
 import org.caosdb.server.permissions.EntityACL;
 import org.caosdb.server.query.Query;
@@ -572,7 +573,7 @@ public abstract class EntityStateJob extends EntityJob {
             final String key = "transition" + refid.toString();
             EntityInterface transition = getCached(key);
             if (transition == null) {
-              transition = retrieveValidEntity(refid);
+              transition = resolve(refid);
               putCache(key, transition);
             }
             result.add(new Transition(transition));
@@ -659,7 +660,7 @@ public abstract class EntityStateJob extends EntityJob {
 
   private EntityInterface retrieveStateEntity(final String stateName) throws Message {
     try {
-      return retrieveValidEntity(retrieveValidIDByName(stateName));
+      return resolve(null, stateName, (String) null);
     } catch (final EntityDoesNotExistException e) {
       throw STATE_NOT_IN_STATE_MODEL;
     }
@@ -667,7 +668,7 @@ public abstract class EntityStateJob extends EntityJob {
 
   private EntityInterface retrieveStateModelEntity(final String stateModel) throws Message {
     try {
-      return retrieveValidEntity(retrieveValidIDByName(stateModel));
+      return resolve(null, stateModel, (String) null);
     } catch (final EntityDoesNotExistException e) {
       throw STATE_MODEL_NOT_FOUND;
     }
@@ -676,7 +677,7 @@ public abstract class EntityStateJob extends EntityJob {
   protected EntityInterface getStateRecordType() throws Message {
     EntityInterface stateRecordType = getCached(STATE_RECORD_TYPE_NAME);
     if (stateRecordType == null) {
-      stateRecordType = retrieveValidSparseEntityByName(STATE_RECORD_TYPE_NAME);
+      stateRecordType = resolve(null, STATE_RECORD_TYPE_NAME, (String) null);
       putCache(STATE_RECORD_TYPE_NAME, stateRecordType);
     }
     return stateRecordType;
@@ -797,7 +798,7 @@ public abstract class EntityStateJob extends EntityJob {
 
       EntityInterface stateEntity = getCached(key);
       if (stateEntity == null) {
-        stateEntity = retrieveValidEntity(refid.getId());
+        stateEntity = resolve(refid.getId());
         putCache(key, stateEntity);
       }
 
@@ -834,7 +835,7 @@ public abstract class EntityStateJob extends EntityJob {
             getUser(),
             c);
     query.execute(getTransaction().getAccess());
-    result = retrieveValidEntity(c.get(0).getId());
+    result = resolve(c.get(0).getId());
     putCache(key, result);
     return result;
   }
@@ -852,6 +853,11 @@ public abstract class EntityStateJob extends EntityJob {
       if (value instanceof DeleteEntity) {
         throw new RuntimeException("Delete entity in cache. This is an implementation error.");
       }
+      if (value instanceof LazyEntityResolver) {
+        // resolve immediately, otherwise the access might be released when
+        // the object is being resolved.
+        ((LazyEntityResolver) value).resolveAll();
+      }
       id_in_cache.add(value.getId());
       cache.put(key, value);
     }
diff --git a/src/main/java/org/caosdb/server/jobs/core/GenerateEntityId.java b/src/main/java/org/caosdb/server/jobs/core/GenerateEntityId.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3b21d9bdf67ad7a1ebe23ea1b77816e72b12de3
--- /dev/null
+++ b/src/main/java/org/caosdb/server/jobs/core/GenerateEntityId.java
@@ -0,0 +1,50 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+package org.caosdb.server.jobs.core;
+
+import org.caosdb.server.entity.EntityInterface;
+import org.caosdb.server.entity.InsertEntity;
+import org.caosdb.server.entity.Message;
+import org.caosdb.server.jobs.EntityJob;
+import org.caosdb.server.jobs.JobAnnotation;
+import org.caosdb.server.jobs.TransactionStage;
+import org.caosdb.server.transaction.WriteTransactionInterface;
+import org.caosdb.server.utils.EntityStatus;
+
+/**
+ * Generates entity ids for newly inserted entities.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+@JobAnnotation(stage = TransactionStage.PRE_TRANSACTION)
+public class GenerateEntityId extends EntityJob {
+
+  @Override
+  protected void run() throws Message {
+    EntityInterface entity = getEntity();
+    if (entity instanceof InsertEntity
+        && getTransaction() instanceof WriteTransactionInterface
+        && entity.getEntityStatus() == EntityStatus.QUALIFIED) {
+      String id = ((WriteTransactionInterface) getTransaction()).generateId();
+      entity.setId(id);
+    }
+  }
+}
diff --git a/src/main/java/org/caosdb/server/jobs/core/Inheritance.java b/src/main/java/org/caosdb/server/jobs/core/Inheritance.java
index a1bd800c7ca40b28d7b9ff27dd8f828ed112891f..70aea11281774230e90e586cad3e897426df8e83 100644
--- a/src/main/java/org/caosdb/server/jobs/core/Inheritance.java
+++ b/src/main/java/org/caosdb/server/jobs/core/Inheritance.java
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,20 +18,16 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
 import java.util.ArrayList;
 import java.util.List;
 import org.caosdb.api.entity.v1.MessageCode;
-import org.caosdb.server.database.backend.transaction.RetrieveFullEntityTransaction;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.InsertEntity;
 import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.Message.MessageType;
-import org.caosdb.server.entity.RetrieveEntity;
 import org.caosdb.server.entity.StatementStatus;
 import org.caosdb.server.entity.UpdateEntity;
 import org.caosdb.server.entity.wrapper.Property;
@@ -88,12 +83,7 @@ public class Inheritance extends EntityJob {
             runJobFromSchedule(getEntity(), CheckParValid.class);
 
             // try to get the parent entity from the current transaction container
-            EntityInterface foreign = getEntityByName(parent.getName());
-            if (foreign == null) {
-              // was not in container -> retrieve from database.
-              execute(new RetrieveFullEntityTransaction(parent));
-              foreign = parent;
-            }
+            EntityInterface foreign = resolve(parent);
 
             collectInheritedProperties(transfer, foreign, inheritance);
           } catch (final IllegalArgumentException e) {
@@ -136,26 +126,24 @@ public class Inheritance extends EntityJob {
               break propertyLoop;
             }
 
-            EntityInterface validProperty = new RetrieveEntity(property.getId());
+            EntityInterface abstractProperty = null;
             if (getEntity().hasParents()) {
               outer:
               for (EntityInterface par : getEntity().getParents()) {
-                if (!par.hasProperties()) {
-                  par = resolve(par);
-                }
+                par = resolve(par);
                 for (final EntityInterface prop : par.getProperties()) {
-                  if (validProperty.hasId() && validProperty.getId().equals(prop.getId())) {
-                    validProperty = prop;
+                  if ((property.hasId() && property.getId().equals(prop.getId()))
+                      || property.hasName() && property.getName().equals(prop.getName())) {
+                    abstractProperty = prop;
                     break outer;
                   }
                 }
               }
-            } else {
-              execute(new RetrieveFullEntityTransaction(validProperty));
             }
-            if (validProperty.getEntityStatus() == EntityStatus.VALID) {
-              collectInheritedProperties(transfer, validProperty, inheritance);
+            if (abstractProperty == null) {
+              abstractProperty = resolve(property);
             }
+            collectInheritedProperties(transfer, abstractProperty, inheritance);
           } catch (final IllegalArgumentException e) {
             property.addWarning(ILLEGAL_INHERITANCE_MODE);
             break propertyLoop;
diff --git a/src/main/java/org/caosdb/server/jobs/core/NoCache.java b/src/main/java/org/caosdb/server/jobs/core/NoCache.java
index e408330ee2639d1c5d7dc5f145848e292daa9b3b..78b54f6c7ecf97669889097241a9ee5f595a9416 100644
--- a/src/main/java/org/caosdb/server/jobs/core/NoCache.java
+++ b/src/main/java/org/caosdb/server/jobs/core/NoCache.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
@@ -26,6 +25,13 @@ import org.caosdb.server.jobs.FlagJob;
 import org.caosdb.server.jobs.JobAnnotation;
 import org.caosdb.server.jobs.TransactionStage;
 
+/**
+ * Turn off caching, just for the current transaction.
+ *
+ * <p>If the caching is disabled globally this has no effect.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 @JobAnnotation(
     flag = "cache",
     defaultValue = "true",
@@ -37,6 +43,6 @@ public class NoCache extends FlagJob {
 
   @Override
   protected void job(final String value) {
-    getTransaction().getAccess().setUseCache(Boolean.valueOf(value));
+    getTransaction().setUseCache(Boolean.valueOf(value));
   }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/core/ProcessNameProperties.java b/src/main/java/org/caosdb/server/jobs/core/ProcessNameProperties.java
index 7196f04edc99cf1269603e820975a96703639965..ecac050455b385d2ecf27bb4ff5d39d46c941508 100644
--- a/src/main/java/org/caosdb/server/jobs/core/ProcessNameProperties.java
+++ b/src/main/java/org/caosdb/server/jobs/core/ProcessNameProperties.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,17 +18,16 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
 import static org.caosdb.server.entity.MagicTypes.NAME;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.Set;
+import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.datatype.AbstractDatatype;
 import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.EntityInterface;
@@ -41,9 +41,13 @@ import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
 /**
- * To be called after CheckPropValid and Inheritance.
+ * Checks if a property is a subproperty of "name" and flags the entity accordingly.
+ *
+ * <p>This enables a different behavior in the search.
  *
- * @author tf
+ * <p>To be called after CheckPropValid and Inheritance.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 @JobAnnotation(stage = TransactionStage.PRE_TRANSACTION)
 public class ProcessNameProperties extends EntityJob {
@@ -133,21 +137,22 @@ public class ProcessNameProperties extends EntityJob {
   }
 
   private Collection<Object> getNearestValidParents(final Property prop) {
-    if (prop.hasId() && !prop.getId().isTemporary()) {
-      final ArrayList<Object> ret = new ArrayList<Object>();
-      if (prop.hasParents()) {
-        for (final Parent par : prop.getParents()) {
+    if (prop.hasParents()) {
+      final Collection<Object> ret = new LinkedList<Object>();
+      for (final Parent par : prop.getParents()) {
+        if (par.hasId()) {
           ret.add(par.getId());
         }
-      } else {
-        ret.add(prop.getId());
       }
       return ret;
     } else if (prop.hasId()) {
-      // property is new -> get valid parents of any depth
-      final EntityInterface propertyEntity = getEntityById(prop.getId());
-      if (propertyEntity != null) {
-        return getNearestValidParents(propertyEntity);
+      try {
+        EntityInterface propertyEntity = resolve(prop.getId());
+        if (propertyEntity != null) {
+          return getNearestValidParents(propertyEntity);
+        }
+      } catch (EntityDoesNotExistException e) {
+        // return null
       }
       return null;
     } else {
diff --git a/src/main/java/org/caosdb/server/jobs/core/ResolveNames.java b/src/main/java/org/caosdb/server/jobs/core/ResolveNames.java
index 5ab722c7176e89485e2bd40dfd515a77bc09e38b..e353375baaaa11c59d7e67c7e39c8cd5a8eb38ee 100644
--- a/src/main/java/org/caosdb/server/jobs/core/ResolveNames.java
+++ b/src/main/java/org/caosdb/server/jobs/core/ResolveNames.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,14 +18,13 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.jobs.core;
 
 import java.util.ArrayList;
 import java.util.List;
 import org.caosdb.server.database.backend.transaction.GetIDByName;
+import org.caosdb.server.database.backend.transaction.RetrieveSparseEntity;
 import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.entity.Entity;
 import org.caosdb.server.entity.EntityID;
@@ -35,6 +35,18 @@ import org.caosdb.server.jobs.ContainerJob;
 import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
+/**
+ * Resolve the names to ids for all entities in the current retrieval.
+ *
+ * <p>If an entity has a name which looks like an id: Check whether that is an existing id first.
+ *
+ * <p>Otherwise, search via the name.
+ *
+ * <p>It there are multiple matching entities, add all of them to the current container. The clients
+ * may handle the ambiguity.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class ResolveNames extends ContainerJob {
 
   @Override
@@ -45,6 +57,20 @@ public class ResolveNames extends ContainerJob {
   public void resolve(final TransactionContainer container) {
     final ArrayList<Entity> add = new ArrayList<Entity>();
     for (final EntityInterface e : container) {
+      if (!e.hasId() && e.hasName() && getTransaction().matchIdPattern(e.getName())) {
+        try {
+          EntityInterface valid =
+              execute(
+                      new RetrieveSparseEntity(
+                          new EntityID(e.getName()),
+                          e.hasVersion() ? e.getVersion().getId() : null))
+                  .getEntity();
+          e.setId(valid.getId());
+        } catch (final EntityDoesNotExistException exc) {
+          // Definitely not an existing id.
+        }
+      }
+
       if (e.hasName() && !e.hasId()) {
         try {
           final List<EntityID> c = execute(new GetIDByName(e.getName(), false)).getList();
diff --git a/src/main/java/org/caosdb/server/jobs/core/UniqueName.java b/src/main/java/org/caosdb/server/jobs/core/UniqueName.java
index 86e6c37e35ec91db647e14e30896abb6b884555b..079afdd9a922fa5758e5f4eb6bec80538338db21 100644
--- a/src/main/java/org/caosdb/server/jobs/core/UniqueName.java
+++ b/src/main/java/org/caosdb/server/jobs/core/UniqueName.java
@@ -40,7 +40,7 @@ public class UniqueName extends FlagJob {
 
       // check against data base
       try {
-        final EntityID foreign = retrieveValidIDByName(entity.getName());
+        final EntityID foreign = retrieveValidIDByName(entity.getName(), null);
         if (entity.hasId() && !foreign.equals(entity.getId())) {
           throw new EntityWasNotUniqueException();
         }
diff --git a/src/main/java/org/caosdb/server/query/CQLLexer.g4 b/src/main/java/org/caosdb/server/query/CQLLexer.g4
index be6dcfa99d2f9c48cba8a0f7fccb7f97b277e01d..f21caf26f0f19d0433b1cdef2d5975d472791e99 100644
--- a/src/main/java/org/caosdb/server/query/CQLLexer.g4
+++ b/src/main/java/org/caosdb/server/query/CQLLexer.g4
@@ -433,7 +433,7 @@ WHITE_SPACE_f:
 
 /** */
 WHITE_SPACE:
-    [ \t\n\r]+
+    WHITE_SPACE_f
 ;
 
 /** */
@@ -529,9 +529,9 @@ COLON:
 
 /** Matches signed and unsigned numbers with decimal points, also numbers in scientific notation. */
 DECIMAL_NUMBER:
-    ((HYPHEN_f | PLUS ) WHITE_SPACE_f?)? 
-    ( NUM_f? DOT NUM_f WHITE_SPACE_f? E_NOTATION_f?
-    | NUM_f WHITE_SPACE_f? E_NOTATION_f
+    ((HYPHEN_f | PLUS ) WHITE_SPACE_f?)?
+    ( NUM_f? DOT NUM_f (WHITE_SPACE_f? E_NOTATION_f)?
+    | NUM_f (WHITE_SPACE_f? E_NOTATION_f)?
     )
 ;
 
diff --git a/src/main/java/org/caosdb/server/query/IDFilter.java b/src/main/java/org/caosdb/server/query/IDFilter.java
index ce01f5f242f914c6f6f812f0875332f7ca004c07..8011139796abff42c0e8109621c849d3e6328137 100644
--- a/src/main/java/org/caosdb/server/query/IDFilter.java
+++ b/src/main/java/org/caosdb/server/query/IDFilter.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.query;
 
@@ -32,24 +31,21 @@ import java.sql.SQLException;
 import org.caosdb.server.query.Query.QueryException;
 import org.jdom2.Element;
 
+/**
+ * Applies an ID filter to the query's current result set.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class IDFilter implements EntityFilterInterface {
 
   private final String operator;
   private final String value;
   private final String aggregate;
-  private final Integer vInt;
 
   public IDFilter(final String o, final String v, final String a) {
     this.operator = o;
     this.value = v;
     this.aggregate = a;
-    Integer i;
-    try {
-      i = Integer.valueOf(v);
-    } catch (final NumberFormatException e) {
-      i = null;
-    }
-    this.vInt = i;
   }
 
   @Override
@@ -79,7 +75,7 @@ public class IDFilter implements EntityFilterInterface {
       if (getValue() == null) {
         callIDFilter.setNull(4, INTEGER);
       } else {
-        callIDFilter.setInt(4, this.vInt);
+        callIDFilter.setString(4, this.getValue());
       }
 
       // aggregate
diff --git a/src/main/java/org/caosdb/server/query/POV.java b/src/main/java/org/caosdb/server/query/POV.java
index ebc35a16b1495accf8cd4a114dd688c2b2529c1b..6ee5f9d0122aa417c357e71ef6d6ea0516007215 100644
--- a/src/main/java/org/caosdb/server/query/POV.java
+++ b/src/main/java/org/caosdb/server/query/POV.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.query;
 
@@ -50,6 +49,11 @@ import org.jdom2.Element;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Applies a POV (Property-operator-value) filter to the query's current result set.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class POV implements EntityFilterInterface {
   public static final Pattern NUMBER_PATTERN =
       Pattern.compile(
@@ -383,8 +387,8 @@ public class POV implements EntityFilterInterface {
         query.getConnection().prepareCall("call initPOVRefidsTable(?,?)")) {
       // stmt = this.connection.prepareCall("call initPOV(?,?,?,?,?)");
       // initPOVRefidsTable(in vInt INT, in vText VARCHAR(255))
-      if (this.vInt != null && this.vInt > 0) {
-        stmt.setInt(1, this.vInt);
+      if (this.value != null) {
+        stmt.setString(1, this.value);
       } else {
         stmt.setNull(1, Types.INTEGER);
       }
diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java
index abaca4365e54c21ee2ba8cf8bf7727fe746c7277..53cd7bf04bccf03eab9422e591750849bfa48728 100644
--- a/src/main/java/org/caosdb/server/query/Query.java
+++ b/src/main/java/org/caosdb/server/query/Query.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -73,7 +73,6 @@ import org.caosdb.server.query.CQLParser.CqContext;
 import org.caosdb.server.query.CQLParsingErrorListener.ParsingError;
 import org.caosdb.server.transaction.TransactionInterface;
 import org.caosdb.server.transaction.WriteTransaction;
-import org.caosdb.server.utils.ResultSetIterator;
 import org.jdom2.Element;
 import org.slf4j.Logger;
 
@@ -218,22 +217,22 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
 
   /** A data class for storing triplets of (Entity ID, version hash, ACL string) */
   public static class IdVersionAclTriplet {
-    public IdVersionAclTriplet(final Integer id, final String version, final String acl) {
+    public IdVersionAclTriplet(final String id, final String version, final String acl) {
       this.id = id;
       this.version = version;
       this.acl = acl;
     }
 
-    public Integer id;
+    public String id;
     public String version;
     public String acl;
 
     @Override
     public String toString() {
       if (version == null) {
-        return Integer.toString(id);
+        return id;
       }
-      return Integer.toString(id) + "@" + version;
+      return id + "@" + version;
     }
 
     @Override
@@ -256,6 +255,14 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     public int hashCode() {
       return toString().hashCode();
     }
+
+    public boolean isInternal() {
+      try {
+        return Integer.parseInt(id) < 100;
+      } catch (NumberFormatException e) {
+        return false;
+      }
+    }
   }
 
   private final boolean filterEntitiesWithoutRetrievePermisions =
@@ -280,6 +287,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
   private final ArrayList<ToElementable> messages = new ArrayList<>();
   private Access access;
   private boolean versioned = false;
+
   /**
    * This key-value cache stores lists of of (id, version hash, acl string) triplets. Those values
    * are the result sets of queries. The keys are created such that they are different for different
@@ -294,8 +302,10 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    */
   private static ICacheAccess<String, Serializable> cache =
       Cache.getCache("HIGH_LEVEL_QUERY_CACHE");
+
   /** Cached=true means that the results of this query have actually been pulled from the cache. */
   private boolean cached = false;
+
   /**
    * Cachable=false means that the results of this query cannot be used for the cache, because the
    * query evaluation contains complex permission checking which could only be cached on a per-user
@@ -327,7 +337,8 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     this.container = container;
     this.query = query;
     this.user = user;
-  };
+  }
+  ;
 
   /**
    * Fill the initially empty resultSet with all entities which match the name, or the id. Then
@@ -412,12 +423,19 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       final Map<EntityID, String> queryTemplates = getQueryTemplates(query, resultSet);
 
       final PreparedStatement removeQTStmt =
-          query.getConnection().prepareStatement("DELETE FROM `" + resultSet + "` WHERE id=?");
+          query
+              .getConnection()
+              .prepareStatement(
+                  "DELETE FROM `"
+                      + resultSet
+                      + "` WHERE EXISTS (SELECT 1 FROM entity_ids AS eids WHERE eids.id=? AND eids.internal_id=`"
+                      + resultSet
+                      + "`.id)");
 
       // Run thru all QTs found...
       for (final Entry<EntityID, String> q : queryTemplates.entrySet()) {
         // ... remove the QT from resultSet...
-        removeQTStmt.setInt(1, q.getKey().toInteger());
+        removeQTStmt.setString(1, q.getKey().toString());
         removeQTStmt.execute();
 
         // ... check for RETRIEVE:ENTITY permission...
@@ -468,12 +486,12 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
           query
               .getConnection()
               .prepareCall(
-                  "SELECT q.id, q.definition FROM query_template_def AS q INNER JOIN `"
+                  "SELECT (SELECT eids.id FROM entity_ids AS eids WHERE eids.internal_id = q.id) as id, q.definition FROM query_template_def AS q INNER JOIN `"
                       + resultSet
                       + "` AS r ON (r.id=q.id);");
       rs = stmt.executeQuery();
       while (rs.next()) {
-        ret.put(new EntityID(rs.getInt("id")), rs.getString("definition"));
+        ret.put(new EntityID(rs.getString("id")), rs.getString("definition"));
       }
       return ret;
     } finally {
@@ -625,7 +643,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     if (this.entity != null) {
       return sourceStrategy(initQuery(versioned));
     } else if (this.role == Role.ENTITY && this.filter == null) {
-      return "entities";
+      return "entity_ids";
     } else {
       return targetStrategy(initQuery(versioned));
     }
@@ -644,29 +662,27 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    */
   private String generateSelectStatementForResultSet(
       final String resultSetTableName, final boolean versioned) {
-    // TODO remove the entities.role part when
-    // https://gitlab.indiscale.com/caosdb/src/caosdb-server/-/issues/245 is resolved
-    if (resultSetTableName.equals("entities")) {
+    if (resultSetTableName.equals("entity_ids")) {
       final String baseStatement =
-          "SELECT entities.id, entity_acl.acl FROM entities INNER JOIN entity_acl ON entity_acl.id=entities.acl WHERE entities.role!='DOMAIN'";
+          "SELECT entities.id AS internal_id, (SELECT id FROM entity_ids WHERE internal_id = entities.id) as id, entity_acl.acl FROM entities INNER JOIN entity_acl ON entity_acl.id=entities.acl";
       if (!versioned) {
         return baseStatement + ";";
       }
       // if versioned, the statement is surrounded with another SELECT and JOIN
       return ("SELECT id, acl, version FROM ("
           + baseStatement
-          + ") AS tmp JOIN entity_version ON entity_version.entity_id=tmp.id;");
+          + ") AS tmp JOIN entity_version ON entity_version.entity_id=tmp.internal_id;");
     } else {
       if (!versioned) {
-        return (" SELECT tmp.id, entity_acl.acl FROM "
+        return (" SELECT (SELECT id FROM entity_ids WHERE internal_id = tmp.id) AS id, entity_acl.acl FROM "
                 + " (SELECT results.id AS id, entities.acl AS acl_id FROM `"
                 + resultSetTableName
-                + "` AS results JOIN entities ON results.id=entities.id WHERE entities.role!='DOMAIN') AS tmp"
+                + "` AS results JOIN entities ON results.id=entities.id) AS tmp"
                 + " JOIN entity_acl ON entity_acl.id=tmp.acl_id")
             + ";";
       }
       // if versioned, the statement is surrounded with another SELECT and JOIN
-      return ("SELECT tmp2.id, acl, version FROM( SELECT tmp.id, entity_acl.acl, tmp._iversion AS _iversion FROM "
+      return ("SELECT (SELECT id FROM entity_ids WHERE internal_id = tmp2.id) AS id, acl, version FROM (SELECT tmp.id, entity_acl.acl, tmp._iversion AS _iversion FROM "
           + " (SELECT results.id AS id, entities.acl AS acl_id, results._iversion AS _iversion FROM `"
           + resultSetTableName
           + "` AS results JOIN entities ON results.id=entities.id) AS tmp"
@@ -692,10 +708,14 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       finishResultSet = finish.executeQuery();
       final List<IdVersionAclTriplet> rs = new LinkedList<>();
       while (finishResultSet.next()) {
+        final String id = finishResultSet.getString("id");
+        if (finishResultSet.wasNull()) {
+          continue;
+        }
         final String version = versioned ? finishResultSet.getString("version") : null;
         final String acl = finishResultSet.getString("acl");
 
-        rs.add(new IdVersionAclTriplet(finishResultSet.getInt("id"), version, acl));
+        rs.add(new IdVersionAclTriplet(id, version, acl));
       }
       return rs;
     } catch (final SQLException e) {
@@ -724,6 +744,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       this.resultSet = getCached(getCacheKey(false));
     }
   }
+
   /** Store the content of `resultSet` member in the high level query cache. */
   private void storeResultInCache() {
     // Decide whether user specific cache needs to be used or not
@@ -735,6 +756,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       cacheItem(getCacheKey(false), this.resultSet);
     }
   }
+
   /** Fill entities from `resultSet` into `container`. */
   private void fillContainerWithResult() {
     if (this.container != null && (this.type == Type.FIND || this.type == Type.SELECT)) {
@@ -786,6 +808,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
     return this;
   }
+
   /** Remove all cached queries from the cache. */
   public static void clearCache() {
     cacheETag = UUID.randomUUID().toString();
@@ -798,7 +821,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     final List<IdVersionAclTriplet> filtered = new ArrayList<>();
     for (final IdVersionAclTriplet triplet : resultSet) {
 
-      if (triplet.id >= 100) {
+      if (!triplet.isInternal()) {
         filtered.add(triplet);
       }
     }
@@ -908,11 +931,11 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
               + "left join entity_acl on entity_n_acl.acl=entity_acl.id;");
       final ResultSet entitiesRS = stmt.executeQuery(query);
       final ResultSetIterator entitiesWithACL = new ResultSetIterator(entitiesRS);
-      final List<Integer> toBeDeleted = collectIdsWithoutPermission(entitiesWithACL);
+      final List<String> toBeDeleted = collectIdsWithoutPermission(entitiesWithACL);
       try (final PreparedStatement pstmt =
           this.getConnection().prepareStatement("DELETE FROM `" + tabname + "` WHERE id = ?")) {
-        for (final Integer id : toBeDeleted) {
-          pstmt.setInt(1, id);
+        for (final String id : toBeDeleted) {
+          pstmt.setString(1, id);
           pstmt.execute();
         }
       }
@@ -931,8 +954,8 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    */
   private List<IdVersionAclTriplet> filterEntitiesWithoutRetrievePermission(
       final List<IdVersionAclTriplet> resultSet) {
-    final List<Integer> toBeDeleted = collectIdsWithoutPermission(resultSet.iterator());
-    final List<IdVersionAclTriplet> filtered = new ArrayList<>();
+    final List<String> toBeDeleted = collectIdsWithoutPermission(resultSet.iterator());
+    final List<IdVersionAclTriplet> filtered = new LinkedList<>();
     for (final IdVersionAclTriplet triplet : resultSet) {
       if (-1 == toBeDeleted.indexOf(triplet.id)) {
         filtered.add(triplet);
@@ -940,6 +963,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
     return filtered;
   }
+
   /**
    * Creates a list with IDs of those entities that do not have sufficient RETRIEVE permission
    *
@@ -947,9 +971,9 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    *     triplets.
    * @return compiled list
    */
-  private List<Integer> collectIdsWithoutPermission(Iterator<IdVersionAclTriplet> entityIterator) {
-    final HashMap<String, Boolean> acl_cache = new HashMap<String, Boolean>();
-    final List<Integer> toBeDeleted = new LinkedList<Integer>();
+  private List<String> collectIdsWithoutPermission(Iterator<IdVersionAclTriplet> entityIterator) {
+    final Map<String, Boolean> acl_cache = new HashMap<>();
+    final List<String> toBeDeleted = new LinkedList<>();
     while (entityIterator.hasNext()) {
       final long t1 = System.currentTimeMillis();
 
@@ -999,7 +1023,9 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     return this.access;
   }
 
-  /** @return the number of entities in the resultset. Might be updated by the filters. */
+  /**
+   * @return the number of entities in the resultset. Might be updated by the filters.
+   */
   @Override
   public int getTargetSetCount() {
     return this.targetSetCount;
diff --git a/src/main/java/org/caosdb/server/utils/ResultSetIterator.java b/src/main/java/org/caosdb/server/query/ResultSetIterator.java
similarity index 95%
rename from src/main/java/org/caosdb/server/utils/ResultSetIterator.java
rename to src/main/java/org/caosdb/server/query/ResultSetIterator.java
index 71429f1a704299555ab1d86be0695e3104be828d..a26c1f41867e96722dd4ba6451344b689d0299e0 100644
--- a/src/main/java/org/caosdb/server/utils/ResultSetIterator.java
+++ b/src/main/java/org/caosdb/server/query/ResultSetIterator.java
@@ -1,4 +1,4 @@
-package org.caosdb.server.utils;
+package org.caosdb.server.query;
 
 import static org.caosdb.server.database.backend.implementation.MySQL.DatabaseUtils.bytes2UTF8;
 
@@ -35,7 +35,8 @@ public class ResultSetIterator implements Iterator<IdVersionAclTriplet> {
       this.cursorHasMoved = true;
     }
     return this.currentIsValid;
-  };
+  }
+  ;
 
   public IdVersionAclTriplet next() {
     if (!this.cursorHasMoved) {
@@ -50,7 +51,7 @@ public class ResultSetIterator implements Iterator<IdVersionAclTriplet> {
       throw new NoSuchElementException();
     }
     try {
-      final Integer id = resultSet.getInt("id");
+      final String id = resultSet.getString("id");
       final String acl_str = bytes2UTF8(resultSet.getBytes("ACL"));
       return new IdVersionAclTriplet(id, "", acl_str);
     } catch (SQLException e) {
diff --git a/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
index 44ebfa22d08c975031f5bf5bfca325d6b706af24..de56fff3207cd554d23badcc63dbd8e5130e6e81 100644
--- a/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
+++ b/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
@@ -243,8 +243,12 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   }
 
   protected abstract Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception;
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception;
 
   @Post
   public Representation httpPost(final Representation entity) {
@@ -277,8 +281,12 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   }
 
   protected Representation httpDeleteInChildClass()
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          Exception {
     getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
     return null;
   }
@@ -293,8 +301,14 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   }
 
   protected Representation httpPostInChildClass(final Representation entity)
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, xmlNotWellFormedException, JDOMException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          xmlNotWellFormedException,
+          JDOMException,
+          Exception {
     getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
     return null;
   }
diff --git a/src/main/java/org/caosdb/server/resource/AuthenticationResource.java b/src/main/java/org/caosdb/server/resource/AuthenticationResource.java
index ed60d7906b1cda003ed2a84f0e22200049d96c25..4f53ba12e958a33d694357372afba274fcfe4151 100644
--- a/src/main/java/org/caosdb/server/resource/AuthenticationResource.java
+++ b/src/main/java/org/caosdb/server/resource/AuthenticationResource.java
@@ -52,8 +52,12 @@ public class AuthenticationResource extends AbstractCaosDBServerResource {
   /** Returns single "Login" element. XSLT will create a form. */
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     final Document doc = new Document();
     final Element rootElem = generateRootElement();
     doc.setRootElement(rootElem);
@@ -66,8 +70,12 @@ public class AuthenticationResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpDeleteInChildClass()
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          Exception {
     final Subject user = SecurityUtils.getSubject();
     if (user.isAuthenticated()) {
       user.logout();
diff --git a/src/main/java/org/caosdb/server/resource/DefaultResource.java b/src/main/java/org/caosdb/server/resource/DefaultResource.java
index 488cd667c8832e4b90277e07144c65cbb7e4036d..39fbf47dcd4cde1d96642a0112b58c3285dec2c9 100644
--- a/src/main/java/org/caosdb/server/resource/DefaultResource.java
+++ b/src/main/java/org/caosdb/server/resource/DefaultResource.java
@@ -43,8 +43,12 @@ public class DefaultResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     final Document doc = new org.jdom2.Document();
     final Element root = generateRootElement();
     if (this.responseBody != null) {
diff --git a/src/main/java/org/caosdb/server/resource/LogoutResource.java b/src/main/java/org/caosdb/server/resource/LogoutResource.java
index 1659f751a4710fbf99fc473b586cc3b180c8a62c..f17bd0c65119bc21183a0d7165a62688e60f2d25 100644
--- a/src/main/java/org/caosdb/server/resource/LogoutResource.java
+++ b/src/main/java/org/caosdb/server/resource/LogoutResource.java
@@ -33,8 +33,12 @@ public class LogoutResource extends AuthenticationResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     return super.httpDeleteInChildClass();
   }
 }
diff --git a/src/main/java/org/caosdb/server/resource/PermissionRulesResource.java b/src/main/java/org/caosdb/server/resource/PermissionRulesResource.java
index 8d2aa1720aaefcdbaccee18c6a1626a912319b6a..afdcb0d60f077ebcfc2dfcc0e99093289a6d621f 100644
--- a/src/main/java/org/caosdb/server/resource/PermissionRulesResource.java
+++ b/src/main/java/org/caosdb/server/resource/PermissionRulesResource.java
@@ -44,8 +44,12 @@ public class PermissionRulesResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     final String role = getRequestedItems()[0];
 
     getUser().checkPermission(ACMPermissions.PERMISSION_RETRIEVE_ROLE_PERMISSIONS(role));
diff --git a/src/main/java/org/caosdb/server/resource/RolesResource.java b/src/main/java/org/caosdb/server/resource/RolesResource.java
index ad1544da3a326f1c16e0b01238985d10e93b0581..73dee43e1f6b49d2c73cf44fe80510bb704d4f0d 100644
--- a/src/main/java/org/caosdb/server/resource/RolesResource.java
+++ b/src/main/java/org/caosdb/server/resource/RolesResource.java
@@ -46,8 +46,12 @@ public class RolesResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     final Element root = generateRootElement();
     final Document document = new Document();
 
@@ -74,8 +78,12 @@ public class RolesResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpDeleteInChildClass()
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          Exception {
     if (getRequestedItems().length > 0) {
       final String name = getRequestedItems()[0];
       if (name != null) {
@@ -97,8 +105,14 @@ public class RolesResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpPostInChildClass(final Representation entity)
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, xmlNotWellFormedException, JDOMException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          xmlNotWellFormedException,
+          JDOMException,
+          Exception {
 
     String name = null;
     String description = null;
diff --git a/src/main/java/org/caosdb/server/resource/ServerLogsResource.java b/src/main/java/org/caosdb/server/resource/ServerLogsResource.java
index f304f10062209d62855a0bff21e0c8cad54e1962..acc1833dc5158d23e72f06f15cf1ddd037185043 100644
--- a/src/main/java/org/caosdb/server/resource/ServerLogsResource.java
+++ b/src/main/java/org/caosdb/server/resource/ServerLogsResource.java
@@ -41,8 +41,12 @@ public class ServerLogsResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
 
     Level level = null;
     String message = null;
diff --git a/src/main/java/org/caosdb/server/resource/UserResource.java b/src/main/java/org/caosdb/server/resource/UserResource.java
index de07331e9637549285d71ca2fd910916cd13316a..ea8e8a264542474cccf74d20cf070342cb43d717 100644
--- a/src/main/java/org/caosdb/server/resource/UserResource.java
+++ b/src/main/java/org/caosdb/server/resource/UserResource.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.resource;
 
@@ -48,14 +47,18 @@ import org.restlet.representation.Representation;
 /**
  * This class handles requests for Users.
  *
- * @author Timm Fitschen
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class UserResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
 
     final Document doc = new Document();
     final Element rootElem = generateRootElement();
@@ -104,12 +107,12 @@ public class UserResource extends AbstractCaosDBServerResource {
           form.getFirstValue("status") != null
               ? UserStatus.valueOf(form.getFirstValue("status").toUpperCase())
               : null;
-      Integer userEntity = null;
+      String userEntity = null;
       if (form.getFirst("entity") != null) {
         if (form.getFirstValue("entity").isEmpty()) {
-          userEntity = 0;
+          userEntity = "";
         } else {
-          userEntity = Integer.parseInt(form.getFirstValue("entity"));
+          userEntity = form.getFirstValue("entity");
         }
       }
 
@@ -150,9 +153,9 @@ public class UserResource extends AbstractCaosDBServerResource {
                     "status",
                     CaosDBServer.getServerProperty(ServerProperties.KEY_NEW_USER_DEFAULT_ACTIVITY))
                 .toUpperCase());
-    Integer userEntity = null;
+    String userEntity = null;
     if (form.getFirst("entity") != null) {
-      userEntity = Integer.parseInt(form.getFirstValue("entity"));
+      userEntity = form.getFirstValue("entity");
     }
 
     final InsertUserTransaction t =
@@ -177,8 +180,12 @@ public class UserResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpDeleteInChildClass()
-      throws ConnectionException, SQLException, CaosDBException, IOException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          SQLException,
+          CaosDBException,
+          IOException,
+          NoSuchAlgorithmException,
+          Exception {
 
     final Document doc = new Document();
     final Element rootElem = generateRootElement();
diff --git a/src/main/java/org/caosdb/server/resource/UserRolesResource.java b/src/main/java/org/caosdb/server/resource/UserRolesResource.java
index 4eb7f6143038bb6e4b0c3fda4646e2730acfea04..72fc906a54b753166a4f5358dfda31ba0dff953e 100644
--- a/src/main/java/org/caosdb/server/resource/UserRolesResource.java
+++ b/src/main/java/org/caosdb/server/resource/UserRolesResource.java
@@ -45,8 +45,12 @@ public class UserRolesResource extends AbstractCaosDBServerResource {
 
   @Override
   protected Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
     final String user = getRequestedItems()[0];
     final String realm =
         (getRequestAttributes().get("realm") != null
diff --git a/src/main/java/org/caosdb/server/resource/transaction/EntityResource.java b/src/main/java/org/caosdb/server/resource/transaction/EntityResource.java
index 4cd7b2fcbd4ae9e9dd3d047555194172c4224d38..833043885ecb0843483417c97cc7569ae316e8ef 100644
--- a/src/main/java/org/caosdb/server/resource/transaction/EntityResource.java
+++ b/src/main/java/org/caosdb/server/resource/transaction/EntityResource.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021,2023 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -53,11 +53,16 @@ import org.restlet.representation.Representation;
  *
  * <p>The GET requests (Retrieval) is handled in the superclass {@link RetrieveEntityResource}.
  *
- * @author Timm Fitschen (t.fitschen@indiscale.com)
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public class EntityResource extends RetrieveEntityResource {
 
-  /** Handle entity deletions (DELETE requests). */
+  /**
+   * Handle entity deletions (DELETE requests).
+   *
+   * <p>Note: The list of entity "specifier" is treated strictly as a list of entity ids. You cannot
+   * delete an entity by name.
+   */
   @Override
   protected final Representation httpDeleteInChildClass() throws Exception {
 
@@ -67,18 +72,14 @@ public class EntityResource extends RetrieveEntityResource {
 
     for (final String item : getRequestedItems()) {
       final String[] elem = item.split("@", 1);
-      Integer id = null;
+      String id = null;
       String version = null;
-      try {
-        id = Integer.parseInt(elem[0]);
-      } catch (final NumberFormatException e) {
-        // pass
-      }
+      id = elem[0];
       if (elem.length > 1) {
         version = elem[1];
       }
 
-      if (id != null && id > 0) {
+      if (id != null) {
         container.add(new DeleteEntity(new EntityID(id), version));
       }
     }
@@ -129,8 +130,12 @@ public class EntityResource extends RetrieveEntityResource {
    * requests which also contain file blobs.
    */
   private Element parseMultipartEntity(final WritableContainer container)
-      throws FileUploadException, IOException, Message, xmlNotWellFormedException,
-          NoSuchAlgorithmException, CaosDBException {
+      throws FileUploadException,
+          IOException,
+          Message,
+          xmlNotWellFormedException,
+          NoSuchAlgorithmException,
+          CaosDBException {
     final DiskFileItemFactory factory = new DiskFileItemFactory();
     factory.setSizeThreshold(1000240);
     final RestletFileUpload upload = new RestletFileUpload(factory);
diff --git a/src/main/java/org/caosdb/server/resource/transaction/RetrieveEntityResource.java b/src/main/java/org/caosdb/server/resource/transaction/RetrieveEntityResource.java
index 6527376d71ba31718394f887b7335615d80db5c6..d5feea9a0fe815004230e697ff0fa38b74fc72b8 100644
--- a/src/main/java/org/caosdb/server/resource/transaction/RetrieveEntityResource.java
+++ b/src/main/java/org/caosdb/server/resource/transaction/RetrieveEntityResource.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021,2023 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -26,8 +26,8 @@ import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
 import org.caosdb.server.CaosDBException;
 import org.caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import org.caosdb.server.entity.EntityID;
 import org.caosdb.server.entity.container.RetrieveContainer;
+import org.caosdb.server.jobs.core.ResolveNames;
 import org.caosdb.server.resource.AbstractCaosDBServerResource;
 import org.caosdb.server.transaction.Retrieve;
 import org.jdom2.Document;
@@ -38,44 +38,40 @@ import org.restlet.representation.Representation;
  * Handles GET requests for different subclasses which all have in common that they retrieve
  * Entities (plus other information in some cases).
  *
- * @author Timm Fitschen (t.fitschen@indiscale.com)
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
  */
 public abstract class RetrieveEntityResource extends AbstractCaosDBServerResource {
 
   /**
-   * Parse the segment which specifies the entities which are to be retrieved
+   * Parse the segment which specifies the entities which are to be retrieved.
    *
-   * @param container
+   * <p>The segments are being treated as names here. The {@link ResolveNames} job is responsible
+   * for detecting whether the name is actually an id.
    */
   protected void handleRetrieveContainer(final RetrieveContainer container) {
 
     for (final String item : getRequestedItems()) {
       final String[] elem = item.split("@", 2);
-      Integer id = null;
-      String name = null;
+      String id = null;
       String version = null;
-      try {
-        id = Integer.parseInt(elem[0]);
-      } catch (final NumberFormatException e) {
-        name = elem[0];
-      }
+      id = elem[0];
       if (elem.length > 1) {
         version = elem[1];
       }
 
-      if (id != null) {
-        container.add(new EntityID(id), version);
-      } else {
-        container.add(name);
-      }
+      container.add(null, id, version);
     }
   }
 
   /** Handle the GET request. */
   @Override
   protected final Representation httpGetInChildClass()
-      throws ConnectionException, IOException, SQLException, CaosDBException,
-          NoSuchAlgorithmException, Exception {
+      throws ConnectionException,
+          IOException,
+          SQLException,
+          CaosDBException,
+          NoSuchAlgorithmException,
+          Exception {
 
     final RetrieveContainer entityContainer =
         new RetrieveContainer(getUser(), getTimestamp(), getSRID(), getFlags());
diff --git a/src/main/java/org/caosdb/server/scripting/ServerSideScriptingCaller.java b/src/main/java/org/caosdb/server/scripting/ServerSideScriptingCaller.java
index edb6b39a4e92466e5a3e5a489669d366bbe8ce37..9a710e25fad549e5d4c14bb623378a2e6aaff806 100644
--- a/src/main/java/org/caosdb/server/scripting/ServerSideScriptingCaller.java
+++ b/src/main/java/org/caosdb/server/scripting/ServerSideScriptingCaller.java
@@ -253,7 +253,9 @@ public class ServerSideScriptingCaller {
     if (pwd.exists()) FileUtils.forceDelete(pwd);
   }
 
-  /** @fixme Should be injected into environment instead. Will be changed in v0.4 of SSS-API */
+  /**
+   * @fixme Should be injected into environment instead. Will be changed in v0.4 of SSS-API
+   */
   String[] injectAuthToken(String[] commandLine) {
     String[] newCommandLine = new String[commandLine.length + 1];
     newCommandLine[0] = commandLine[0];
diff --git a/src/main/java/org/caosdb/server/transaction/EntityTransactionInterface.java b/src/main/java/org/caosdb/server/transaction/EntityTransactionInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d96c4e7499728ca11c348ac1875d94ece100a72
--- /dev/null
+++ b/src/main/java/org/caosdb/server/transaction/EntityTransactionInterface.java
@@ -0,0 +1,37 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.transaction;
+
+import org.caosdb.server.entity.EntityID;
+
+/**
+ * This interface is implemented by all transactions of entities (as opposed to transaction which
+ * only concern users or other kinds of transactions).
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public interface EntityTransactionInterface extends TransactionInterface {
+
+  public boolean matchIdPattern(String id);
+
+  public default boolean matchIdPattern(EntityID id) {
+    return id != null && matchIdPattern(id.toString());
+  }
+}
diff --git a/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java b/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java
index f3f4c7f5fd583ff0ff16d4fd1ce583394258f35b..3174dabf4e3d6a581f27aaf59cb8ffd866401bf5 100644
--- a/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java
@@ -50,7 +50,7 @@ public class InsertUserTransaction extends AccessControlTransaction {
       final String password,
       final String email,
       final UserStatus status,
-      final Integer entity) {
+      final String entity) {
     this(new ProtoUser(), password);
     this.user.realm = UserSources.getInternalRealm().getName();
     this.user.name = username;
diff --git a/src/main/java/org/caosdb/server/transaction/ListRolesTransaction.java b/src/main/java/org/caosdb/server/transaction/ListRolesTransaction.java
index ed3cd3cc5a154e82946e76f9934ee8608fe6980c..f0b0db78eeff6c04ca466dbd6f65f8350fbab783 100644
--- a/src/main/java/org/caosdb/server/transaction/ListRolesTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/ListRolesTransaction.java
@@ -39,9 +39,7 @@ public class ListRolesTransaction extends AccessControlTransaction {
   protected void transaction() throws Exception {
     Subject currentUser = SecurityUtils.getSubject();
     roles =
-        execute(new ListRoles(), getAccess())
-            .getRoles()
-            .stream()
+        execute(new ListRoles(), getAccess()).getRoles().stream()
             .filter(
                 role ->
                     currentUser.isPermitted(
diff --git a/src/main/java/org/caosdb/server/transaction/ListUsersTransaction.java b/src/main/java/org/caosdb/server/transaction/ListUsersTransaction.java
index 2ade4e8595f159d1fc6996c1e04913f4195ecd97..fe9b9c172d2c6b4361790d30590650ae0233a2ad 100644
--- a/src/main/java/org/caosdb/server/transaction/ListUsersTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/ListUsersTransaction.java
@@ -37,9 +37,7 @@ public class ListUsersTransaction extends AccessControlTransaction {
   protected void transaction() throws Exception {
     Subject currentUser = SecurityUtils.getSubject();
     users =
-        execute(new ListUsers(), getAccess())
-            .getUsers()
-            .stream()
+        execute(new ListUsers(), getAccess()).getUsers().stream()
             .filter(
                 user ->
                     currentUser.isPermitted(
diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveACL.java b/src/main/java/org/caosdb/server/transaction/RetrieveACL.java
index ac0a2896451a43ca10985bd38787ad4f847a05cc..b5a4a489c60269dbae906bba1942f8e9525eb710 100644
--- a/src/main/java/org/caosdb/server/transaction/RetrieveACL.java
+++ b/src/main/java/org/caosdb/server/transaction/RetrieveACL.java
@@ -40,7 +40,7 @@ public class RetrieveACL extends Transaction<TransactionContainer> {
         new TransactionContainer(
             SecurityUtils.getSubject(), System.currentTimeMillis(), UUID.randomUUID().toString()));
     for (String strId : idList) {
-      getContainer().add(new RetrieveEntity(new EntityID(Integer.parseInt(strId))));
+      getContainer().add(new RetrieveEntity(new EntityID(strId)));
     }
   }
 
diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java b/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java
index eb24fb24db4f1b6a50a279cfcd9e158003a70948..72a1d61929e692e551a53013ac1aabb1a4f28f5a 100644
--- a/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java
@@ -77,7 +77,7 @@ public class RetrieveUserTransaction extends AccessControlTransaction {
       ret.setAttribute("email", user.email);
     }
     if (user.entity != null) {
-      ret.setAttribute("entity", Integer.toString(user.entity));
+      ret.setAttribute("entity", user.entity);
     }
     if (user.status != null) {
       ret.setAttribute("status", user.status.toString());
diff --git a/src/main/java/org/caosdb/server/transaction/Transaction.java b/src/main/java/org/caosdb/server/transaction/Transaction.java
index 5fc06f5ec82066d3515cbf524e64beb001ba0fcd..69dde0ea3602a650e52dadcdbc0107ff7cf12ded 100644
--- a/src/main/java/org/caosdb/server/transaction/Transaction.java
+++ b/src/main/java/org/caosdb/server/transaction/Transaction.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2021,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2021,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -21,8 +21,12 @@
  */
 package org.caosdb.server.transaction;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.shiro.subject.Subject;
 import org.caosdb.datetime.UTCDateTime;
 import org.caosdb.server.accessControl.Principal;
@@ -31,6 +35,7 @@ import org.caosdb.server.database.access.Access;
 import org.caosdb.server.database.backend.transaction.InsertTransactionHistory;
 import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.database.misc.TransactionBenchmark;
+import org.caosdb.server.entity.EntityIdRegistry;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.container.TransactionContainer;
@@ -47,9 +52,89 @@ import org.caosdb.server.permissions.EntityACL;
 import org.caosdb.server.utils.AbstractObservable;
 import org.caosdb.server.utils.Info;
 import org.caosdb.server.utils.Observer;
+import org.caosdb.server.utils.UseCacheResource;
+import org.caosdb.server.utils.UseCacheResourceDelegate;
 
+/**
+ * The NoOpCache is used when the caching is diabled (globally or for the current transaction.
+ *
+ * <p>It results in much simpler code when the callers do not need to check whether the caching is
+ * active all the time.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+@SuppressWarnings("rawtypes")
+class NoOpCache implements Map {
+
+  @Override
+  public int size() {
+    // TODO Auto-generated method stub
+    return 0;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return false;
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return false;
+  }
+
+  @Override
+  public Object get(Object key) {
+    return null;
+  }
+
+  @Override
+  public Object put(Object key, Object value) {
+    return null;
+  }
+
+  @Override
+  public Object remove(Object key) {
+    return null;
+  }
+
+  @Override
+  public void putAll(Map m) {}
+
+  @Override
+  public void clear() {}
+
+  @Override
+  public Set keySet() {
+    return Collections.EMPTY_SET;
+  }
+
+  @Override
+  public Collection values() {
+    return Collections.EMPTY_LIST;
+  }
+
+  @Override
+  public Set entrySet() {
+    return Collections.EMPTY_SET;
+  }
+}
+
+/**
+ * Abstract base implementation for all EntityTransactions (Transaction involving entities).
+ *
+ * <p>Handles caching, benchmark timing, the access to the back end, generates and checks entity
+ * ids, holds the state of the transaction and triggers the scheduler to run the jobs.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public abstract class Transaction<C extends TransactionContainer> extends AbstractObservable
-    implements TransactionInterface {
+    implements EntityTransactionInterface, UseCacheResource {
 
   @Override
   public TransactionBenchmark getTransactionBenchmark() {
@@ -59,6 +144,8 @@ public abstract class Transaction<C extends TransactionContainer> extends Abstra
   private static final DatabaseAccessManager monitor = DatabaseAccessManager.getInstance();
 
   public static final String CLEAN_UP = "TransactionCleanUp";
+
+  protected EntityIdRegistry idRegistry = null;
   private final C container;
   private Access access = null;
   private final Schedule schedule = new Schedule();
@@ -270,61 +357,104 @@ public abstract class Transaction<C extends TransactionContainer> extends Abstra
     }
   }
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected void rollBack() {
     this.schedule.runJobs(TransactionStage.ROLL_BACK);
   }
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void init() throws Exception;
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void preCheck() throws InterruptedException, Exception;
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected final void check() {
     this.schedule.runJobs(TransactionStage.CHECK);
   }
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void postCheck();
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void preTransaction() throws InterruptedException;
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void transaction() throws Exception;
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void postTransaction() throws Exception;
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected abstract void cleanUp();
 
-  /** @see {@link #execute()} */
+  /**
+   * @see {@link #execute()}
+   */
   protected void commit() throws Exception {}
 
-  public boolean useCache() {
-    return getContainer().getFlags() != null
-        && !getContainer().getFlags().containsKey("disableCache");
-  }
-
   public final Access getAccess() {
     return this.access;
   }
 
   protected void setAccess(final Access a) {
     this.access = a;
+    if (access != null) {
+      this.access.setUseCacheResourceDelegate(useCacheResourceDelegate);
+    }
   }
 
   @SuppressWarnings("unchecked")
-  public <S, T> HashMap<S, T> getCache(final String name) {
+  public <S, T> Map<S, T> getCache(final String name) {
+    if (!useCache()) {
+      return NO_OP_CACHE;
+    }
     if (!this.caches.containsKey(name)) {
       this.caches.put(name, new HashMap<S, T>());
     }
     return this.caches.get(name);
   }
 
+  private static final NoOpCache NO_OP_CACHE = new NoOpCache();
+
   @SuppressWarnings("rawtypes")
-  private final HashMap<String, HashMap> caches = new HashMap<>();
+  private final Map<String, Map> caches = new HashMap<>();
+
+  private final UseCacheResource useCacheResourceDelegate = new UseCacheResourceDelegate();
+
+  @Override
+  public UseCacheResource getUseCacheResourceDelegate() {
+    return this.useCacheResourceDelegate.getUseCacheResourceDelegate();
+  }
+
+  @Override
+  public void setUseCacheResourceDelegate(UseCacheResource delegate) {
+    this.useCacheResourceDelegate.setUseCacheResourceDelegate(delegate);
+  }
+
+  @Override
+  public boolean matchIdPattern(String id) {
+    if (this.idRegistry == null) {
+      this.idRegistry = new EntityIdRegistry(this);
+    }
+    return idRegistry.matchIdPattern(id);
+  }
 }
diff --git a/src/main/java/org/caosdb/server/transaction/UpdateACL.java b/src/main/java/org/caosdb/server/transaction/UpdateACL.java
index 84c73080550d8899f4f1a5156bebb2a44c39df6a..289b5d53a14c642b4ac85bd9c02dd5c69484fa91 100644
--- a/src/main/java/org/caosdb/server/transaction/UpdateACL.java
+++ b/src/main/java/org/caosdb/server/transaction/UpdateACL.java
@@ -143,4 +143,10 @@ public class UpdateACL extends Transaction<TransactionContainer>
   public String getSRID() {
     return getContainer().getRequestId();
   }
+
+  @Override
+  public String generateId() {
+    throw new UnsupportedOperationException(
+        "This is not implemented on purpose. This exception indicates a usage error of this UpdateACL class.");
+  }
 }
diff --git a/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java b/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java
index 6808968f20574242cfdaa9b87793d7a4ad4b6914..7730d82b2fc2fb7ff3d34430ea3d1b60ffb9c16e 100644
--- a/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java
@@ -63,7 +63,7 @@ public class UpdateUserTransaction extends AccessControlTransaction {
       final String username,
       final UserStatus status,
       final String email,
-      final Integer entity,
+      final String entity,
       final String password) {
     this.user = new ProtoUser();
     this.user.realm =
@@ -177,7 +177,7 @@ public class UpdateUserTransaction extends AccessControlTransaction {
           ACMPermissions.PERMISSION_UPDATE_USER_ENTITY(this.user.realm, this.user.name));
       isToBeUpdated = true;
 
-      if (this.user.entity.equals(0)) {
+      if (this.user.entity.isEmpty()) {
         // this means that the entity is to be reset.
         this.user.entity = null;
       } else {
diff --git a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
index 47b7a53c71ddebb7c1b062c2c8599cf44eabe039..b780d3d68f20cb6973c902cbe92fbd4fd46d51c1 100644
--- a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java
@@ -3,8 +3,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2019-2022 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2019-2022 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2019-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2019-2023 Timm Fitschen <t.fitschen@indiscale.com>
  * Copyright (C) 2022 Daniel Hornung <d.hornung@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -40,6 +40,7 @@ import org.caosdb.server.database.backend.transaction.UpdateEntityTransaction;
 import org.caosdb.server.database.misc.RollBackHandler;
 import org.caosdb.server.entity.DeleteEntity;
 import org.caosdb.server.entity.EntityID;
+import org.caosdb.server.entity.EntityIdRegistry;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.FileProperties;
 import org.caosdb.server.entity.InsertEntity;
@@ -593,4 +594,13 @@ public class WriteTransaction extends Transaction<WritableContainer>
   public String getSRID() {
     return getContainer().getRequestId();
   }
+
+  @Override
+  public String generateId() {
+    if (this.idRegistry == null) {
+      this.idRegistry = new EntityIdRegistry(this);
+    }
+
+    return this.idRegistry.generate();
+  }
 }
diff --git a/src/main/java/org/caosdb/server/transaction/WriteTransactionInterface.java b/src/main/java/org/caosdb/server/transaction/WriteTransactionInterface.java
index 4e2938e18d061cbd1a7575baa59322356731859a..c39d2c14a7dc625b1aa8bf0529feaeec2c4ca8b3 100644
--- a/src/main/java/org/caosdb/server/transaction/WriteTransactionInterface.java
+++ b/src/main/java/org/caosdb/server/transaction/WriteTransactionInterface.java
@@ -10,4 +10,6 @@ public interface WriteTransactionInterface extends TransactionInterface {
   public Subject getTransactor();
 
   public String getSRID();
+
+  public String generateId();
 }
diff --git a/src/main/java/org/caosdb/server/utils/AbstractObservable.java b/src/main/java/org/caosdb/server/utils/AbstractObservable.java
index abc7f0a0ae1cdcbeff613c2778637de97a507c57..1bb4fc472a90c05d656f0d4250299801b73f07a2 100644
--- a/src/main/java/org/caosdb/server/utils/AbstractObservable.java
+++ b/src/main/java/org/caosdb/server/utils/AbstractObservable.java
@@ -37,7 +37,9 @@ public abstract class AbstractObservable implements Observable {
     return this.observers.add(o);
   }
 
-  /** @param e A String denoting the notification event. */
+  /**
+   * @param e A String denoting the notification event.
+   */
   @Override
   public void notifyObservers(final String e) {
     if (this.observers != null) {
diff --git a/src/main/java/org/caosdb/server/utils/UseCacheResource.java b/src/main/java/org/caosdb/server/utils/UseCacheResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..89057f51c59f0f99a3eed3346ec18ab29ada74c0
--- /dev/null
+++ b/src/main/java/org/caosdb/server/utils/UseCacheResource.java
@@ -0,0 +1,41 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.utils;
+
+/**
+ * Interface which indicates that a class can turn on and off the caching of the current transaction
+ * and inform the caller about the state of the transactions's caching.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public interface UseCacheResource {
+
+  public default boolean useCache() {
+    return getUseCacheResourceDelegate().useCache();
+  }
+
+  public default void setUseCache(boolean useCache) {
+    getUseCacheResourceDelegate().setUseCache(useCache);
+  }
+
+  public void setUseCacheResourceDelegate(UseCacheResource delegate);
+
+  public UseCacheResource getUseCacheResourceDelegate();
+}
diff --git a/src/main/java/org/caosdb/server/utils/UseCacheResourceDelegate.java b/src/main/java/org/caosdb/server/utils/UseCacheResourceDelegate.java
new file mode 100644
index 0000000000000000000000000000000000000000..c537f0a813fe149b7338909f0dc95e8f3728dec1
--- /dev/null
+++ b/src/main/java/org/caosdb/server/utils/UseCacheResourceDelegate.java
@@ -0,0 +1,70 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.caosdb.server.utils;
+
+import org.caosdb.server.CaosDBServer;
+
+/**
+ * Basic implementation of the {@link UseCacheResource} interface.
+ *
+ * <p>This implementation uses a Delegator Pattern to link different UseCacheResources together.
+ * This is uses to delegate the responsibility to the transaction as the final Object of the
+ * delegation.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class UseCacheResourceDelegate implements UseCacheResource {
+  private boolean useCache = CaosDBServer.useCache();
+  private UseCacheResource delegate = null;
+
+  @Override
+  public void setUseCache(boolean useCache) {
+    if (this.delegate != null) {
+      this.delegate.setUseCache(useCache);
+    } else {
+      this.useCache = useCache;
+    }
+  }
+
+  @Override
+  public boolean useCache() {
+    if (delegate != null) {
+      return delegate.useCache();
+    }
+    return CaosDBServer.useCache() && useCache;
+  }
+
+  @Override
+  public void setUseCacheResourceDelegate(UseCacheResource delegate) {
+    if (delegate == this) {
+      this.delegate = null;
+    } else {
+      this.delegate = delegate;
+    }
+  }
+
+  @Override
+  public UseCacheResource getUseCacheResourceDelegate() {
+    if (this.delegate != null) {
+      return this.delegate;
+    }
+    return this;
+  }
+}
diff --git a/src/test/java/org/caosdb/server/caching/TestCaching.java b/src/test/java/org/caosdb/server/caching/TestCaching.java
index 1aba2ff6f16cea7a1f62e84e50e2cc9797114e27..8ff05660afde6e67d65e94011b662f09bdda9294 100644
--- a/src/test/java/org/caosdb/server/caching/TestCaching.java
+++ b/src/test/java/org/caosdb/server/caching/TestCaching.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.caching;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -17,6 +36,7 @@ public class TestCaching {
   @BeforeAll
   public static void init() throws IOException {
     CaosDBServer.initServerProperties();
+    CaosDBServer.initCaching();
     JCSCacheHelper.init();
   }
 
diff --git a/src/test/java/org/caosdb/server/caching/TestNoCaching.java b/src/test/java/org/caosdb/server/caching/TestNoCaching.java
index 4fc73adf89f9355d1ff6addcd0f71fd9eda4e653..7eeeee71a909a106ad93b8c440ad895e366cca5f 100644
--- a/src/test/java/org/caosdb/server/caching/TestNoCaching.java
+++ b/src/test/java/org/caosdb/server/caching/TestNoCaching.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.caching;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -17,6 +36,7 @@ public class TestNoCaching {
   public static void init() throws IOException {
     CaosDBServer.initServerProperties();
     CaosDBServer.setProperty(ServerProperties.KEY_CACHE_DISABLE, "TRUE");
+    CaosDBServer.initCaching();
     JCSCacheHelper.init();
   }
 
diff --git a/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java b/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java
index 03bd185c8884822f89f8ff323a1c32125b66f88b..feee1360bf7fa0ae865422b31d8a2ad2bcf64ebe 100644
--- a/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java
+++ b/src/test/java/org/caosdb/server/database/backend/implementation/MySQL/InsertTest.java
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.implementation.MySQL;
 
@@ -50,7 +49,7 @@ public class InsertTest {
   private Deque<EntityID> registerReplacementIds(int count) {
     Deque<EntityID> replacementIds = new ArrayDeque<>();
     for (int i = 1; i < count + 1; i++) {
-      replacementIds.add(new EntityID(-i));
+      replacementIds.add(new EntityID(Integer.toString(-i)));
     }
     return replacementIds;
   }
@@ -63,70 +62,70 @@ public class InsertTest {
   @Test
   public void testTransformation1() throws Exception {
     final Entity r = new InsertEntity("Test", Role.Record);
-    final Property p1 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p1 = new Property(new RetrieveEntity(new EntityID("1")));
     p1.setRole("Property");
     p1.setValue(new GenericValue("V1"));
     p1.setDatatype("TEXT");
     p1.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p1);
 
-    final Property p2 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p2 = new Property(new RetrieveEntity(new EntityID("2")));
     p2.setRole("Property");
     p2.setValue(new GenericValue("V2"));
     p2.setDatatype("TEXT");
     p2.setStatementStatus(StatementStatus.RECOMMENDED);
     r.addProperty(p2);
 
-    final Property p3 = new Property(new RetrieveEntity(new EntityID(3)));
+    final Property p3 = new Property(new RetrieveEntity(new EntityID("3")));
     p3.setRole("Property");
     p3.setValue(new GenericValue("V3"));
     p3.setDatatype("TEXT");
     p3.setStatementStatus(StatementStatus.OBLIGATORY);
     p2.addProperty(p3);
 
-    final Property p4 = new Property(new RetrieveEntity(new EntityID(4)));
+    final Property p4 = new Property(new RetrieveEntity(new EntityID("4")));
     p4.setRole("Property");
     p4.setValue(new GenericValue("V4"));
     p4.setDatatype("TEXT");
     p4.setStatementStatus(StatementStatus.OBLIGATORY);
     r.addProperty(p4);
 
-    final Property p5 = new Property(new RetrieveEntity(new EntityID(5)));
+    final Property p5 = new Property(new RetrieveEntity(new EntityID("5")));
     p5.setRole("Property");
     p5.setValue(new GenericValue("V5"));
     p5.setDatatype("TEXT");
     p5.setStatementStatus(StatementStatus.OBLIGATORY);
     p4.addProperty(p5);
 
-    final Property p6 = new Property(new RetrieveEntity(new EntityID(6)));
+    final Property p6 = new Property(new RetrieveEntity(new EntityID("6")));
     p6.setRole("Property");
     p6.setValue(new GenericValue("V6"));
     p6.setDatatype("TEXT");
     p6.setStatementStatus(StatementStatus.OBLIGATORY);
     p5.addProperty(p6);
 
-    final Property p7 = new Property(new RetrieveEntity(new EntityID(7)));
+    final Property p7 = new Property(new RetrieveEntity(new EntityID("7")));
     p7.setRole("Property");
     p7.setValue(new GenericValue("V7"));
     p7.setDatatype("TEXT");
     p7.setStatementStatus(StatementStatus.OBLIGATORY);
     r.addProperty(p7);
 
-    final Property p8 = new Property(new RetrieveEntity(new EntityID(8)));
+    final Property p8 = new Property(new RetrieveEntity(new EntityID("8")));
     p8.setRole("Property");
     p8.setValue(new GenericValue("V8"));
     p8.setDatatype("TEXT");
     p8.setStatementStatus(StatementStatus.OBLIGATORY);
     p7.addProperty(p8);
 
-    final Property p9 = new Property(new RetrieveEntity(new EntityID(9)));
+    final Property p9 = new Property(new RetrieveEntity(new EntityID("9")));
     p9.setRole("Property");
     p9.setValue(new GenericValue("V9"));
     p9.setDatatype("TEXT");
     p9.setStatementStatus(StatementStatus.OBLIGATORY);
     p8.addProperty(p9);
 
-    final Property p10 = new Property(new RetrieveEntity(new EntityID(10)));
+    final Property p10 = new Property(new RetrieveEntity(new EntityID("10")));
     p10.setRole("Property");
     p10.setValue(new GenericValue("V10"));
     p10.setDatatype("TEXT");
@@ -143,57 +142,57 @@ public class InsertTest {
 
     assertEquals(7, stage1Inserts.size());
     assertFalse(stage1Inserts.get(0) instanceof Replacement);
-    assertEquals(1, stage1Inserts.get(0).getId().toInteger());
+    assertEquals("1", stage1Inserts.get(0).getId().toString());
     assertEquals("V1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString());
 
     assertFalse(stage1Inserts.get(1) instanceof Replacement);
-    assertEquals(2, stage1Inserts.get(1).getId().toInteger());
+    assertEquals("2", stage1Inserts.get(1).getId().toString());
     assertEquals("V2", ((SingleValue) stage1Inserts.get(1).getValue()).toDatabaseString());
 
     assertFalse(stage1Inserts.get(2) instanceof Replacement);
-    assertEquals(4, stage1Inserts.get(2).getId().toInteger());
+    assertEquals("4", stage1Inserts.get(2).getId().toString());
     assertEquals("V4", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString());
 
     assertTrue(stage1Inserts.get(3) instanceof Replacement);
-    assertEquals(-1, stage1Inserts.get(3).getId().toInteger());
+    assertEquals("-1", stage1Inserts.get(3).getId().toString());
     assertEquals("V5", ((SingleValue) stage1Inserts.get(3).getValue()).toDatabaseString());
 
     assertFalse(stage1Inserts.get(4) instanceof Replacement);
-    assertEquals(7, stage1Inserts.get(4).getId().toInteger());
+    assertEquals("7", stage1Inserts.get(4).getId().toString());
     assertEquals("V7", ((SingleValue) stage1Inserts.get(4).getValue()).toDatabaseString());
 
     assertTrue(stage1Inserts.get(5) instanceof Replacement);
-    assertEquals(-2, stage1Inserts.get(5).getId().toInteger());
+    assertEquals("-2", stage1Inserts.get(5).getId().toString());
     assertEquals("V8", ((SingleValue) stage1Inserts.get(5).getValue()).toDatabaseString());
 
     assertTrue(stage1Inserts.get(6) instanceof Replacement);
-    assertEquals(-3, stage1Inserts.get(6).getId().toInteger());
+    assertEquals("-3", stage1Inserts.get(6).getId().toString());
     assertEquals("V9", ((SingleValue) stage1Inserts.get(6).getValue()).toDatabaseString());
 
     assertEquals(6, stage2Inserts.size());
-    assertEquals(new EntityID(3), stage2Inserts.get(0).getId());
+    assertEquals(new EntityID("3"), stage2Inserts.get(0).getId());
     assertEquals("V3", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString());
-    assertEquals(new EntityID(2), stage2Inserts.get(0).getDomain());
+    assertEquals(new EntityID("2"), stage2Inserts.get(0).getDomain());
 
-    assertEquals(new EntityID(5), stage2Inserts.get(1).getId());
+    assertEquals(new EntityID("5"), stage2Inserts.get(1).getId());
     assertEquals("V5", ((SingleValue) stage2Inserts.get(1).getValue()).toDatabaseString());
-    assertEquals(new EntityID(4), stage2Inserts.get(1).getDomain());
+    assertEquals(new EntityID("4"), stage2Inserts.get(1).getDomain());
 
-    assertEquals(new EntityID(6), stage2Inserts.get(2).getId());
+    assertEquals(new EntityID("6"), stage2Inserts.get(2).getId());
     assertEquals("V6", ((SingleValue) stage2Inserts.get(2).getValue()).toDatabaseString());
-    assertEquals(new EntityID(-1), stage2Inserts.get(2).getDomain());
+    assertEquals(new EntityID("-1"), stage2Inserts.get(2).getDomain());
 
-    assertEquals(new EntityID(8), stage2Inserts.get(3).getId());
+    assertEquals(new EntityID("8"), stage2Inserts.get(3).getId());
     assertEquals("V8", ((SingleValue) stage2Inserts.get(3).getValue()).toDatabaseString());
-    assertEquals(new EntityID(7), stage2Inserts.get(3).getDomain());
+    assertEquals(new EntityID("7"), stage2Inserts.get(3).getDomain());
 
-    assertEquals(new EntityID(9), stage2Inserts.get(4).getId());
+    assertEquals(new EntityID("9"), stage2Inserts.get(4).getId());
     assertEquals("V9", ((SingleValue) stage2Inserts.get(4).getValue()).toDatabaseString());
-    assertEquals(new EntityID(-2), stage2Inserts.get(4).getDomain());
+    assertEquals(new EntityID("-2"), stage2Inserts.get(4).getDomain());
 
-    assertEquals(new EntityID(10), stage2Inserts.get(5).getId());
+    assertEquals(new EntityID("10"), stage2Inserts.get(5).getId());
     assertEquals("V10", ((SingleValue) stage2Inserts.get(5).getValue()).toDatabaseString());
-    assertEquals(new EntityID(-3), stage2Inserts.get(5).getDomain());
+    assertEquals(new EntityID("-3"), stage2Inserts.get(5).getDomain());
   }
 
   /**
@@ -205,21 +204,21 @@ public class InsertTest {
   @Test
   public void testTransformation2() throws Exception {
     final Entity r = new InsertEntity("Test", Role.Record);
-    final Property p1 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p1 = new Property(new RetrieveEntity(new EntityID("1")));
     p1.setRole("Property");
     p1.setValue(new GenericValue("V1-1"));
     p1.setDatatype("TEXT");
     p1.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p1);
 
-    final Property p2 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p2 = new Property(new RetrieveEntity(new EntityID("1")));
     p2.setRole("Property");
     p2.setValue(new GenericValue("V1-2"));
     p2.setDatatype("TEXT");
     p2.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p2);
 
-    final Property subp = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property subp = new Property(new RetrieveEntity(new EntityID("2")));
     subp.setRole("Property");
     subp.setValue(new GenericValue("V2"));
     subp.setDatatype("TEXT");
@@ -235,21 +234,21 @@ public class InsertTest {
     assertEquals(3, stage1Inserts.size());
 
     assertFalse(stage1Inserts.get(0) instanceof Replacement);
-    assertEquals(new EntityID(1), stage1Inserts.get(0).getId());
+    assertEquals(new EntityID("1"), stage1Inserts.get(0).getId());
     assertEquals("V1-1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString());
 
     assertTrue(stage1Inserts.get(1) instanceof Replacement);
     assertEquals("V1-2", ((SingleValue) stage1Inserts.get(1).getValue()).toDatabaseString());
-    assertEquals(new EntityID(-1), stage1Inserts.get(1).getId());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(1).getId());
 
     assertFalse(stage1Inserts.get(2) instanceof Replacement);
-    assertEquals(new EntityID(-1), stage1Inserts.get(2).getId());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(2).getId());
     assertEquals("1", ((SingleValue) stage1Inserts.get(2).getValue()).toDatabaseString());
 
     assertEquals(1, stage2Inserts.size());
 
     assertFalse(stage2Inserts.get(0) instanceof Replacement);
-    assertEquals(new EntityID(2), stage2Inserts.get(0).getId());
+    assertEquals(new EntityID("2"), stage2Inserts.get(0).getId());
     assertEquals("V2", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString());
   }
 
@@ -262,25 +261,25 @@ public class InsertTest {
   @Test
   public void testTransformation3() throws Exception {
     final Entity r = new InsertEntity("Test", Role.Record);
-    final Property p1 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p1 = new Property(new RetrieveEntity(new EntityID("1")));
     p1.setRole("Property");
     p1.setDatatype("TEXT");
     p1.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p1);
 
-    final Property p2 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p2 = new Property(new RetrieveEntity(new EntityID("1")));
     p2.setRole("Property");
     p2.setDatatype("TEXT");
     p2.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p2);
 
-    final Property p3 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p3 = new Property(new RetrieveEntity(new EntityID("1")));
     p3.setRole("Property");
     p3.setDatatype("TEXT");
     p3.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p3);
 
-    final Property sub1 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property sub1 = new Property(new RetrieveEntity(new EntityID("2")));
     sub1.setRole("Property");
     sub1.setDatatype("TEXT");
     sub1.setValue(new GenericValue("V1"));
@@ -295,25 +294,25 @@ public class InsertTest {
 
     assertEquals(4, stage1Inserts.size());
     assertTrue(stage1Inserts.get(0) instanceof Replacement);
-    assertEquals(new EntityID(-1), stage1Inserts.get(0).getId());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(0).getId());
     assertEquals(null, stage1Inserts.get(0).getValue());
 
     assertFalse(stage1Inserts.get(1) instanceof Replacement);
-    assertEquals(new EntityID(-1), stage1Inserts.get(1).getId());
-    assertEquals(1, ((ReferenceValue) stage1Inserts.get(1).getValue()).getId().toInteger());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(1).getId());
+    assertEquals("1", ((ReferenceValue) stage1Inserts.get(1).getValue()).getId().toString());
 
     assertFalse(stage1Inserts.get(2) instanceof Replacement);
-    assertEquals(new EntityID(1), stage1Inserts.get(2).getId());
+    assertEquals(new EntityID("1"), stage1Inserts.get(2).getId());
     assertEquals(null, stage1Inserts.get(2).getValue());
 
     assertFalse(stage1Inserts.get(3) instanceof Replacement);
-    assertEquals(new EntityID(1), stage1Inserts.get(3).getId());
+    assertEquals(new EntityID("1"), stage1Inserts.get(3).getId());
     assertEquals(null, stage1Inserts.get(3).getValue());
 
     assertEquals(1, stage2Inserts.size());
-    assertEquals(new EntityID(2), stage2Inserts.get(0).getId());
+    assertEquals(new EntityID("2"), stage2Inserts.get(0).getId());
     assertEquals("V1", ((SingleValue) stage2Inserts.get(0).getValue()).toDatabaseString());
-    assertEquals(new EntityID(-1), stage2Inserts.get(0).getDomain());
+    assertEquals(new EntityID("-1"), stage2Inserts.get(0).getDomain());
   }
 
   /**
@@ -325,14 +324,14 @@ public class InsertTest {
   public void testTransformation4() throws Exception {
 
     final Entity r = new InsertEntity("Test", Role.Record);
-    final Property p1 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p1 = new Property(new RetrieveEntity(new EntityID("1")));
     p1.setRole("Property");
     p1.setDatatype("TEXT");
     p1.setValue(new GenericValue("V1"));
     p1.setStatementStatus(StatementStatus.FIX);
     r.addProperty(p1);
 
-    final Property p2 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p2 = new Property(new RetrieveEntity(new EntityID("2")));
     p2.setRole("Property");
     p2.setDatatype("LIST<TEXT>");
     p2.setStatementStatus(StatementStatus.FIX);
@@ -343,7 +342,7 @@ public class InsertTest {
     p2.setValue(vals);
     r.addProperty(p2);
 
-    final Property p3 = new Property(new RetrieveEntity(new EntityID(3)));
+    final Property p3 = new Property(new RetrieveEntity(new EntityID("3")));
     p3.setRole("Property");
     p3.setDatatype("TEXT");
     p3.setValue(new GenericValue("V3"));
@@ -359,19 +358,19 @@ public class InsertTest {
     assertEquals(4, stage1Inserts.size());
 
     assertFalse(stage1Inserts.get(0) instanceof Replacement);
-    assertEquals(new EntityID(1), stage1Inserts.get(0).getId());
+    assertEquals(new EntityID("1"), stage1Inserts.get(0).getId());
     assertEquals("V1", ((SingleValue) stage1Inserts.get(0).getValue()).toDatabaseString());
 
     assertTrue(stage1Inserts.get(1) instanceof Replacement);
-    assertEquals(new EntityID(-1), stage1Inserts.get(1).getId());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(1).getId());
     assertTrue(stage1Inserts.get(1).getValue() instanceof CollectionValue);
 
     assertFalse(stage1Inserts.get(2) instanceof Replacement);
-    assertEquals(new EntityID(-1), stage1Inserts.get(2).getId());
-    assertEquals(2, ((ReferenceValue) stage1Inserts.get(2).getValue()).getId().toInteger());
+    assertEquals(new EntityID("-1"), stage1Inserts.get(2).getId());
+    assertEquals("2", ((ReferenceValue) stage1Inserts.get(2).getValue()).getId().toString());
 
     assertFalse(stage1Inserts.get(3) instanceof Replacement);
-    assertEquals(new EntityID(3), stage1Inserts.get(3).getId());
+    assertEquals(new EntityID("3"), stage1Inserts.get(3).getId());
     assertEquals("V3", ((SingleValue) stage1Inserts.get(3).getValue()).toDatabaseString());
 
     assertEquals(0, stage2Inserts.size());
@@ -381,7 +380,7 @@ public class InsertTest {
   @Test
   public void testTransformation5() {
     final Entity r = new InsertEntity("Test", Role.RecordType);
-    final Property p1 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p1 = new Property(new RetrieveEntity(new EntityID("1")));
     p1.setRole("Property");
     p1.setDatatype("TEXT");
     p1.setDescription("desc1");
@@ -391,7 +390,7 @@ public class InsertTest {
     p1.setStatementStatus(StatementStatus.RECOMMENDED);
     r.addProperty(p1);
 
-    final Property p2 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p2 = new Property(new RetrieveEntity(new EntityID("2")));
     p2.setRole("Property");
     p2.setDatatype("TEXT");
     p2.setDescription("desc2");
@@ -401,7 +400,7 @@ public class InsertTest {
     p2.setStatementStatus(StatementStatus.RECOMMENDED);
     r.addProperty(p2);
 
-    final Property p21 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p21 = new Property(new RetrieveEntity(new EntityID("1")));
     p21.setRole("Property");
     p21.setDatatype("TEXT");
     p21.setDescription("desc21");
@@ -411,7 +410,7 @@ public class InsertTest {
     p21.setStatementStatus(StatementStatus.FIX);
     p2.addProperty(p21);
 
-    final Property p22 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p22 = new Property(new RetrieveEntity(new EntityID("2")));
     p22.setRole("Property");
     p22.setDatatype("TEXT");
     p22.setDescription("desc22");
@@ -421,7 +420,7 @@ public class InsertTest {
     p22.setStatementStatus(StatementStatus.FIX);
     p2.addProperty(p22);
 
-    final Property p3 = new Property(new RetrieveEntity(new EntityID(3)));
+    final Property p3 = new Property(new RetrieveEntity(new EntityID("3")));
     p3.setRole("Property");
     p3.setDatatype("TEXT");
     p3.setDescription("desc3");
@@ -431,7 +430,7 @@ public class InsertTest {
     p3.setStatementStatus(StatementStatus.RECOMMENDED);
     r.addProperty(p3);
 
-    final Property p31 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p31 = new Property(new RetrieveEntity(new EntityID("1")));
     p31.setRole("Property");
     p31.setDatatype("TEXT");
     p31.setDescription("desc31");
@@ -441,7 +440,7 @@ public class InsertTest {
     p31.setStatementStatus(StatementStatus.FIX);
     p3.addProperty(p31);
 
-    final Property p32 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p32 = new Property(new RetrieveEntity(new EntityID("2")));
     p32.setRole("Property");
     p32.setDatatype("TEXT");
     p32.setDescription("desc32");
@@ -451,7 +450,7 @@ public class InsertTest {
     p32.setStatementStatus(StatementStatus.FIX);
     p3.addProperty(p32);
 
-    final Property p321 = new Property(new RetrieveEntity(new EntityID(1)));
+    final Property p321 = new Property(new RetrieveEntity(new EntityID("1")));
     p321.setRole("Property");
     p321.setDatatype("TEXT");
     p321.setDescription("desc321");
@@ -461,7 +460,7 @@ public class InsertTest {
     p321.setStatementStatus(StatementStatus.FIX);
     p32.addProperty(p321);
 
-    final Property p322 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Property p322 = new Property(new RetrieveEntity(new EntityID("2")));
     p322.setRole("Property");
     p322.setDatatype("TEXT");
     p322.setDescription("desc322");
@@ -471,7 +470,7 @@ public class InsertTest {
     p322.setStatementStatus(StatementStatus.FIX);
     p32.addProperty(p322);
 
-    final Property p323 = new Property(new RetrieveEntity(new EntityID(3)));
+    final Property p323 = new Property(new RetrieveEntity(new EntityID("3")));
     p323.setRole("Property");
     p323.setDatatype("TEXT");
     p323.setDescription("desc323");
@@ -481,7 +480,7 @@ public class InsertTest {
     p323.setStatementStatus(StatementStatus.FIX);
     p32.addProperty(p323);
 
-    final Property p33 = new Property(new RetrieveEntity(new EntityID(3)));
+    final Property p33 = new Property(new RetrieveEntity(new EntityID("3")));
     p33.setRole("Property");
     p33.setDatatype("TEXT");
     p33.setDescription("desc33");
diff --git a/src/test/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java b/src/test/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java
index 72c84d1f7b262a854a257c8ae764d4e3da9b8e80..cfd8fcc9ba39cdf68dbf43be77de30f81c4fbec9 100644
--- a/src/test/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java
+++ b/src/test/java/org/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java
@@ -1,9 +1,8 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.database.backend.transaction;
 
@@ -43,32 +40,33 @@ public class RetrieveFullEntityTest {
   @Test
   public void testRetrieveSubEntities() {
     final RetrieveFullEntityTransaction r =
-        new RetrieveFullEntityTransaction(new EntityID(0)) {
+        new RetrieveFullEntityTransaction(new EntityID("0")) {
 
           /** Mock-up */
           @Override
           public void retrieveFullEntity(
               final EntityInterface e, final List<Selection> selections) {
             // The id of the referenced window
-            assertEquals(new EntityID(1234), e.getId());
+            assertEquals(new EntityID("1234"), e.getId());
 
             // The level of selectors has been reduced by 1
             assertEquals("description", selections.get(0).getSelector());
 
             e.setDescription("A heart-shaped window.");
-          };
+          }
+          ;
         };
 
-    final Property window = new Property(new RetrieveEntity(new EntityID(2345)));
+    final Property window = new Property(new RetrieveEntity(new EntityID("2345")));
     window.setName("Window");
     window.setDatatype("Window");
-    window.setValue(new ReferenceValue(1234));
+    window.setValue(new ReferenceValue("1234"));
 
-    final Entity house = new RetrieveEntity(new EntityID(3456));
+    final Entity house = new RetrieveEntity(new EntityID("3456"));
     house.addProperty(window);
     final ReferenceValue value =
-        (ReferenceValue) house.getProperties().getEntityById(new EntityID(2345)).getValue();
-    assertEquals(new EntityID(1234), value.getId());
+        (ReferenceValue) house.getProperties().getEntityById(new EntityID("2345")).getValue();
+    assertEquals(new EntityID("1234"), value.getId());
     assertNull(value.getEntity());
 
     final List<Selection> selections = new ArrayList<>();
@@ -76,7 +74,7 @@ public class RetrieveFullEntityTest {
 
     r.retrieveSubEntities(house, selections);
 
-    assertEquals(new EntityID(1234), value.getId());
+    assertEquals(new EntityID("1234"), value.getId());
     assertNotNull(value.getEntity());
     assertEquals("A heart-shaped window.", value.getEntity().getDescription());
   }
diff --git a/src/test/java/org/caosdb/server/entity/container/PropertyContainerTest.java b/src/test/java/org/caosdb/server/entity/container/PropertyContainerTest.java
index a8ccdbdc9f7a9522020332e01cba96a1667d70b6..f8fb0217adb0cc35cbc51d90b96f76d5f7b3592e 100644
--- a/src/test/java/org/caosdb/server/entity/container/PropertyContainerTest.java
+++ b/src/test/java/org/caosdb/server/entity/container/PropertyContainerTest.java
@@ -1,9 +1,8 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.entity.container;
 
@@ -48,7 +45,7 @@ public class PropertyContainerTest {
 
   @BeforeAll
   public static void setup() {
-    window = new RetrieveEntity(new EntityID(1234));
+    window = new RetrieveEntity(new EntityID("1234"));
     windowHeight = new Property(new RetrieveEntity("window.height", Role.Property));
     window.addProperty(windowHeight);
     windowHeight.setValue(new GenericValue("windowHeight"));
@@ -59,7 +56,7 @@ public class PropertyContainerTest {
     houseHeight = new Property(new RetrieveEntity("height", Role.Property));
     houseHeight.setValue(new GenericValue("houseHeight"));
     house.addProperty(houseHeight);
-    windowProperty = new Property(new RetrieveEntity(new EntityID(2345)));
+    windowProperty = new Property(new RetrieveEntity(new EntityID("2345")));
     windowProperty.setName("window");
     windowProperty.setValue(new ReferenceValue(window.getId()));
     house.addProperty(windowProperty);
diff --git a/src/test/java/org/caosdb/server/entity/xml/PropertyToElementStrategyTest.java b/src/test/java/org/caosdb/server/entity/xml/PropertyToElementStrategyTest.java
index a2c9676b9759fc55fb0d1e089808ab50d016288e..bab174c88ed595ec4b79b1cf47b1cf2dbb0cbc95 100644
--- a/src/test/java/org/caosdb/server/entity/xml/PropertyToElementStrategyTest.java
+++ b/src/test/java/org/caosdb/server/entity/xml/PropertyToElementStrategyTest.java
@@ -1,9 +1,8 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 package org.caosdb.server.entity.xml;
 
@@ -66,7 +63,7 @@ public class PropertyToElementStrategyTest {
 
   @BeforeEach
   public void setup() {
-    window = new RetrieveEntity(new EntityID(1234), Role.Record);
+    window = new RetrieveEntity(new EntityID("1234"), Role.Record);
     windowHeight = new Property(new RetrieveEntity("height", Role.Property));
     window.addProperty(windowHeight);
     windowHeight.setValue(new GenericValue("windowHeight"));
@@ -77,7 +74,7 @@ public class PropertyToElementStrategyTest {
     houseHeight = new Property(new RetrieveEntity("height", Role.Property));
     houseHeight.setValue(new GenericValue("houseHeight"));
     house.addProperty(houseHeight);
-    windowProperty = new Property(new RetrieveEntity(new EntityID(2345)));
+    windowProperty = new Property(new RetrieveEntity(new EntityID("2345")));
     windowProperty.setName("window");
     windowProperty.setDatatype("window");
     windowProperty.setValue(new ReferenceValue(window.getId()));
diff --git a/src/test/java/org/caosdb/server/grpc/CaosDBToGrpcConvertersTest.java b/src/test/java/org/caosdb/server/grpc/CaosDBToGrpcConvertersTest.java
index d46c187324b76e179ef8d562cd5a150ab7968a45..ad85d3d4c00727134440d0f4eaa1a424fb550372 100644
--- a/src/test/java/org/caosdb/server/grpc/CaosDBToGrpcConvertersTest.java
+++ b/src/test/java/org/caosdb/server/grpc/CaosDBToGrpcConvertersTest.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.grpc;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -74,7 +93,7 @@ public class CaosDBToGrpcConvertersTest {
     RetrieveEntity entity = new RetrieveEntity();
 
     // must be printed
-    entity.setId(new EntityID(1234));
+    entity.setId(new EntityID("1234"));
     entity.addInfo("info");
     entity.addWarning(new Message("warning"));
     entity.addError(new Message("error"));
@@ -136,7 +155,7 @@ public class CaosDBToGrpcConvertersTest {
 
     RetrieveEntity person1 = new RetrieveEntity();
     person1.addProperty(fullName1);
-    ReferenceValue val1 = new ReferenceValue(new EntityID(1234));
+    ReferenceValue val1 = new ReferenceValue(new EntityID("1234"));
     val1.setEntity(person1, false);
     col.add(val1);
 
@@ -147,7 +166,7 @@ public class CaosDBToGrpcConvertersTest {
 
     RetrieveEntity person2 = new RetrieveEntity();
     person2.addProperty(fullName2);
-    ReferenceValue val2 = new ReferenceValue(new EntityID(1234));
+    ReferenceValue val2 = new ReferenceValue(new EntityID("1234"));
     val2.setEntity(person2, false);
     col.add(val2);
     p.setValue(col);
diff --git a/src/test/java/org/caosdb/server/jobs/JobConfigTest.java b/src/test/java/org/caosdb/server/jobs/JobConfigTest.java
index e176c2111189fb52ca9946e10ae5ec705549b6c8..c097d0a76ec5444881e9dd58bb735015b9fe8db1 100644
--- a/src/test/java/org/caosdb/server/jobs/JobConfigTest.java
+++ b/src/test/java/org/caosdb/server/jobs/JobConfigTest.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.jobs;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -26,7 +45,7 @@ public class JobConfigTest {
     final JobConfig jobConfig = JobConfig.getInstance();
     assertEquals("Retrieve", jobConfig.getTransactionType(new RetrieveEntity("test")));
     assertEquals("Insert", jobConfig.getTransactionType(new InsertEntity("test", Role.Record)));
-    assertEquals("Delete", jobConfig.getTransactionType(new DeleteEntity(new EntityID(1234))));
+    assertEquals("Delete", jobConfig.getTransactionType(new DeleteEntity(new EntityID("1234"))));
     assertEquals("Update", jobConfig.getTransactionType(new UpdateEntity(new Element("Record"))));
   }
 }
diff --git a/src/test/java/org/caosdb/server/query/TestCQL.java b/src/test/java/org/caosdb/server/query/TestCQL.java
index 8d7a7e8fb219f286d6cdaffc4b28240a7b2897d5..61a87b7f5764a8da26bc7bb6ccd8f06a320302f1 100644
--- a/src/test/java/org/caosdb/server/query/TestCQL.java
+++ b/src/test/java/org/caosdb/server/query/TestCQL.java
@@ -36,6 +36,7 @@ import java.util.regex.Matcher;
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.Vocabulary;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.caosdb.server.CaosDBServer;
 import org.caosdb.server.database.access.Access;
@@ -3546,7 +3547,10 @@ public class TestCQL {
    */
   @Test
   public void TestTicket147i()
-      throws InterruptedException, SQLException, ConnectionException, QueryException,
+      throws InterruptedException,
+          SQLException,
+          ConnectionException,
+          QueryException,
           TransactionException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.ticket147i));
@@ -6754,6 +6758,7 @@ public class TestCQL {
     // must not throw ParsingException
     new Query(this.queryIssue134).parse();
   }
+
   /**
    * Space before special character unit
    *
@@ -7103,4 +7108,32 @@ public class TestCQL {
     assertTrue(conj.getFilters().get(0) instanceof POV);
     assertTrue(conj.getFilters().get(1) instanceof POV);
   }
+
+  @Test
+  public void testDecimalNumber() {
+    // This should always be DEC, WHITESPACE, AND  repeat
+    final String text =
+        "1.2123e+3 AND 1.21234E+3 AND 1.21234E-3 AND 1.21234E3 AND 16.0 AND 1.2 AND -1.2 AND +1.2 AND 1.2 AND - 1.2 AND + 1.2 AND 2e-323 AND 2E-323 AND 2E- 323 AND 2 e -323 AND + 1.2123e+323";
+    CQLLexer lexer = new CQLLexer(CharStreams.fromString(text));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+    Vocabulary vocab = lexer.getVocabulary();
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+    int no = 0;
+    for (final Token t : tokens.getTokens()) {
+      if (no % 3 == 0) {
+        assertEquals(vocab.getSymbolicName(t.getType()), "DECIMAL_NUMBER");
+      }
+      if (no % 3 == 1) {
+        if (vocab.getSymbolicName(t.getType()) != "EOF") {
+          assertEquals(vocab.getSymbolicName(t.getType()), "WHITE_SPACE");
+        }
+      }
+      if (no % 3 == 2) {
+        assertEquals(vocab.getSymbolicName(t.getType()), "AND");
+      }
+      no = no + 1;
+    }
+  }
 }
diff --git a/src/test/java/org/caosdb/server/resource/TestAbstractCaosDBServerResource.java b/src/test/java/org/caosdb/server/resource/TestAbstractCaosDBServerResource.java
index ca4fbb0954f469055c2da3d0bf00b03cdc9dd563..4da4ba5cb4959787f5aaf1bf12e47140fdf4ee00 100644
--- a/src/test/java/org/caosdb/server/resource/TestAbstractCaosDBServerResource.java
+++ b/src/test/java/org/caosdb/server/resource/TestAbstractCaosDBServerResource.java
@@ -95,8 +95,12 @@ public class TestAbstractCaosDBServerResource {
 
           @Override
           protected Representation httpGetInChildClass()
-              throws ConnectionException, IOException, SQLException, CaosDBException,
-                  NoSuchAlgorithmException, Exception {
+              throws ConnectionException,
+                  IOException,
+                  SQLException,
+                  CaosDBException,
+                  NoSuchAlgorithmException,
+                  Exception {
             // TODO Auto-generated method stub
             return null;
           }
diff --git a/src/test/java/org/caosdb/server/resource/TestScriptingResource.java b/src/test/java/org/caosdb/server/resource/TestScriptingResource.java
index 31d4a384c4a2a7e12b48c99073119cb7a38e3acc..3ce449ae2eea5ab5b4487ee4c14c22692423c8aa 100644
--- a/src/test/java/org/caosdb/server/resource/TestScriptingResource.java
+++ b/src/test/java/org/caosdb/server/resource/TestScriptingResource.java
@@ -178,12 +178,12 @@ public class TestScriptingResource {
             return 0;
           }
           return -1;
-        };
+        }
 
         @Override
         public Element generateRootElement(ServerSideScriptingCaller caller) {
           return new Element("OK");
-        };
+        }
 
         @Override
         public Object generateAuthToken(String purpose) {
diff --git a/src/test/java/org/caosdb/server/transaction/RetrieveTest.java b/src/test/java/org/caosdb/server/transaction/RetrieveTest.java
index a3ac40e1bf1e0fe6489a74f45d6c253b903b4478..95a019d46d9325759a3ad032ec285e98c9e51210 100644
--- a/src/test/java/org/caosdb/server/transaction/RetrieveTest.java
+++ b/src/test/java/org/caosdb/server/transaction/RetrieveTest.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 package org.caosdb.server.transaction;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -62,7 +81,7 @@ public class RetrieveTest {
   public void testMissingRetrievePermission() {
     Subject subject = SecurityUtils.getSubject();
     subject.login(AnonymousAuthenticationToken.getInstance());
-    EntityInterface entity = new RetrieveEntity(new EntityID(1234));
+    EntityInterface entity = new RetrieveEntity(new EntityID("1234"));
     EntityACLFactory fac = new EntityACLFactory();
     fac.deny(AnonymousAuthenticationToken.PRINCIPAL, "RETRIEVE:ENTITY");
     entity.setEntityACL(fac.create());
diff --git a/src/test/java/org/caosdb/server/transaction/UpdateTest.java b/src/test/java/org/caosdb/server/transaction/UpdateTest.java
index a0891a3eb34e1759100c78916d0fb250de149ef8..9a138106f4313f06ac2457728e3b5bd218470fa5 100644
--- a/src/test/java/org/caosdb/server/transaction/UpdateTest.java
+++ b/src/test/java/org/caosdb/server/transaction/UpdateTest.java
@@ -3,8 +3,9 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2022 Indiscale GmbH <info@indiscale.com>
+ * Copyright (C) 2022,2023 Indiscale GmbH <info@indiscale.com>
  * Copyright (C) 2022 Daniel Hornung <d.hornung@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -75,11 +76,11 @@ public class UpdateTest {
   @Test
   public void testDeriveUpdate_SameProperty()
       throws NoSuchAlgorithmException, IOException, CaosDBException {
-    final Entity newEntity = new RetrieveEntity(new EntityID(1234));
-    final Property newProperty = new Property(new RetrieveEntity(new EntityID(1)));
+    final Entity newEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property newProperty = new Property(new RetrieveEntity(new EntityID("1")));
     newEntity.addProperty(newProperty);
-    final Property oldProperty = new Property(new RetrieveEntity(new EntityID(1)));
-    final Entity oldEntity = new RetrieveEntity(new EntityID(1234));
+    final Property oldProperty = new Property(new RetrieveEntity(new EntityID("1")));
+    final Entity oldEntity = new RetrieveEntity(new EntityID("1234"));
     oldEntity.addProperty(oldProperty);
 
     new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
@@ -89,13 +90,13 @@ public class UpdateTest {
   @Test
   public void testDeriveUpdate_AnotherProperty()
       throws NoSuchAlgorithmException, IOException, CaosDBException {
-    final Entity newEntity = new RetrieveEntity(new EntityID(1234));
-    final Property newProperty = new Property(new RetrieveEntity(new EntityID(1)));
-    final Property newProperty2 = new Property(new RetrieveEntity(new EntityID(2)));
+    final Entity newEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property newProperty = new Property(new RetrieveEntity(new EntityID("1")));
+    final Property newProperty2 = new Property(new RetrieveEntity(new EntityID("2")));
     newEntity.addProperty(newProperty);
     newEntity.addProperty(newProperty2);
-    final Property oldProperty = new Property(new RetrieveEntity(new EntityID(1)));
-    final Entity oldEntity = new RetrieveEntity(new EntityID(1234));
+    final Property oldProperty = new Property(new RetrieveEntity(new EntityID("1")));
+    final Entity oldEntity = new RetrieveEntity(new EntityID("1234"));
     oldEntity.addProperty(oldProperty);
 
     new WriteTransaction(null).deriveUpdate(newEntity, oldEntity);
@@ -107,15 +108,15 @@ public class UpdateTest {
   @Test
   public void testDeriveUpdate_SameUnit()
       throws NoSuchAlgorithmException, IOException, CaosDBException {
-    final EntityInterface magicUnit = new RetrieveEntity(new EntityID(1234));
+    final EntityInterface magicUnit = new RetrieveEntity(new EntityID("1234"));
     magicUnit.setName("Unit");
-    magicUnit.setId(new EntityID(24));
+    magicUnit.setId(new EntityID("24"));
     magicUnit.setDatatype("TEXT");
 
-    final Entity newEntity = new RetrieveEntity(new EntityID(1234));
-    final Property newProperty = new Property(new RetrieveEntity(new EntityID(1)));
+    final Entity newEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property newProperty = new Property(new RetrieveEntity(new EntityID("1")));
 
-    final Property newUnit = new Property(new RetrieveEntity(new EntityID(5)));
+    final Property newUnit = new Property(new RetrieveEntity(new EntityID("5")));
     newUnit.setName(magicUnit.getName());
     newUnit.setId(magicUnit.getId());
     newUnit.setDatatype(magicUnit.getDatatype());
@@ -126,10 +127,10 @@ public class UpdateTest {
 
     newEntity.addProperty(newProperty);
 
-    final Entity oldEntity = new RetrieveEntity(new EntityID(1234));
-    final Property oldProperty = new Property(new RetrieveEntity(new EntityID(1)));
+    final Entity oldEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property oldProperty = new Property(new RetrieveEntity(new EntityID("1")));
 
-    final Property oldUnit = new Property(new RetrieveEntity(new EntityID(5)));
+    final Property oldUnit = new Property(new RetrieveEntity(new EntityID("5")));
     oldUnit.setName(magicUnit.getName());
     oldUnit.setId(magicUnit.getId());
     oldUnit.setDatatype(magicUnit.getDatatype());
@@ -149,15 +150,15 @@ public class UpdateTest {
   @Test
   public void testDeriveUpdate_DifferentUnit()
       throws NoSuchAlgorithmException, IOException, CaosDBException {
-    final EntityInterface magicUnit = new RetrieveEntity(new EntityID(1234));
+    final EntityInterface magicUnit = new RetrieveEntity(new EntityID("1234"));
     magicUnit.setName("Unit");
-    magicUnit.setId(new EntityID(24));
+    magicUnit.setId(new EntityID("24"));
     magicUnit.setDatatype("TEXT");
 
-    final Entity newEntity = new RetrieveEntity(new EntityID(1234));
-    final Property newProperty = new Property(new RetrieveEntity(new EntityID(1)));
+    final Entity newEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property newProperty = new Property(new RetrieveEntity(new EntityID("1")));
 
-    final Property newUnit = new Property(new RetrieveEntity(new EntityID(5)));
+    final Property newUnit = new Property(new RetrieveEntity(new EntityID("5")));
     newUnit.setName(magicUnit.getName());
     newUnit.setId(magicUnit.getId());
     newUnit.setDatatype(magicUnit.getDatatype());
@@ -168,10 +169,10 @@ public class UpdateTest {
 
     newEntity.addProperty(newProperty);
 
-    final Entity oldEntity = new RetrieveEntity(new EntityID(1234));
-    final Property oldProperty = new Property(new RetrieveEntity(new EntityID(1)));
+    final Entity oldEntity = new RetrieveEntity(new EntityID("1234"));
+    final Property oldProperty = new Property(new RetrieveEntity(new EntityID("1")));
 
-    final Property oldUnit = new Property(new RetrieveEntity(new EntityID(5)));
+    final Property oldUnit = new Property(new RetrieveEntity(new EntityID("5")));
     oldUnit.setName(magicUnit.getName());
     oldUnit.setId(magicUnit.getId());
     oldUnit.setDatatype(magicUnit.getDatatype());
@@ -192,10 +193,10 @@ public class UpdateTest {
       throws NoSuchAlgorithmException, CaosDBException, IOException {
 
     final Entity newEntity = new UpdateEntity();
-    final Property newProperty = new Property(new UpdateEntity(new EntityID(1)));
+    final Property newProperty = new Property(new UpdateEntity(new EntityID("1")));
     newProperty.setDatatype("List<Person>");
     CollectionValue newValue = new CollectionValue();
-    newValue.add(new ReferenceValue(1234));
+    newValue.add(new ReferenceValue("1234"));
     newValue.add(null);
     newValue.add(new GenericValue(2345));
     newValue.add(new GenericValue(3465));
@@ -206,14 +207,14 @@ public class UpdateTest {
 
     // old entity represents the stored entity.
     final Entity oldEntity = new UpdateEntity();
-    final Property oldProperty = new Property(new UpdateEntity(new EntityID(1)));
+    final Property oldProperty = new Property(new UpdateEntity(new EntityID("1")));
     oldProperty.setDatatype("List<Person>");
     CollectionValue oldValue = new CollectionValue();
     // Values are shuffled but have the correct index
     oldValue.add(1, null);
     oldValue.add(3, new GenericValue(3465));
-    oldValue.add(2, new ReferenceValue(2345));
-    oldValue.add(0, new ReferenceValue(1234));
+    oldValue.add(2, new ReferenceValue("2345"));
+    oldValue.add(0, new ReferenceValue("1234"));
     oldProperty.setValue(oldValue);
     oldEntity.addProperty(oldProperty);
 
@@ -245,8 +246,8 @@ public class UpdateTest {
     // Values are shuffled but have the correct index
     oldValue2.add(0, null);
     oldValue2.add(1, new GenericValue(3465));
-    oldValue2.add(2, new ReferenceValue(2345));
-    oldValue2.add(3, new ReferenceValue(1234));
+    oldValue2.add(2, new ReferenceValue("2345"));
+    oldValue2.add(3, new ReferenceValue("1234"));
     oldValue2.add(4, null);
     oldProperty.setValue(oldValue2);
 
@@ -266,8 +267,8 @@ public class UpdateTest {
   public void testDeriveUpdate_UpdateList()
       throws NoSuchAlgorithmException, CaosDBException, IOException {
     // @review Florian Spreckelsen 2022-03-15
-    final Property oldProperty = new Property(new UpdateEntity(new EntityID(1)));
-    final Property newProperty = new Property(new UpdateEntity(new EntityID(1)));
+    final Property oldProperty = new Property(new UpdateEntity(new EntityID("1")));
+    final Property newProperty = new Property(new UpdateEntity(new EntityID("1")));
     oldProperty.setDatatype("List<Person>");
     newProperty.setDatatype("List<Person>");
     final Entity oldEntity = new UpdateEntity();
diff --git a/src/test/java/org/caosdb/server/utils/FileUtilsTest.java b/src/test/java/org/caosdb/server/utils/FileUtilsTest.java
index e05a3c7f6f082f2432137737c5937e67ff75d4ef..36851c4eacc7d78c4fcfd033f16c53f5e086b49b 100644
--- a/src/test/java/org/caosdb/server/utils/FileUtilsTest.java
+++ b/src/test/java/org/caosdb/server/utils/FileUtilsTest.java
@@ -573,7 +573,10 @@ public class FileUtilsTest {
 
   @Test
   public void testFileSystemConsistencyCheck()
-      throws NoSuchAlgorithmException, IOException, TransactionException, InterruptedException,
+      throws NoSuchAlgorithmException,
+          IOException,
+          TransactionException,
+          InterruptedException,
           Message {
     final String rootPath = "./testFileSystemConsistencyCheck/";
     final File root = new File(rootPath);