diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 083090b871f199ea2ef24728a7f46fd9b862527c..31f0e81d6a8fc8e55a6005b86d7160c834a2dfd7 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -36,7 +36,7 @@ set(libcaosdb_INCL
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/message_code.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table.h
-    #${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_set.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_set.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/status_code.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.h
diff --git a/include/caosdb/result_set.h b/include/caosdb/result_set.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8510da18b24e81c402ea4dad89afeb7c40a200c
--- /dev/null
+++ b/include/caosdb/result_set.h
@@ -0,0 +1,125 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021 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
+ * 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/>.
+ *
+ */
+#ifndef CAOSDB_RESULT_SET_H
+#define CAOSDB_RESULT_SET_H
+
+#include "caosdb/entity.h" // for Entity, FileDe...
+#include <algorithm>       // for max
+#include <iterator>        // for iterator, next
+#include <memory>          // for unique_ptr
+#include <utility>         // for move
+#include <vector>          // for vector
+// IWYU pragma: no_include <ext/alloc_traits.h>
+
+namespace caosdb::transaction {
+using caosdb::entity::Entity;
+
+/**
+ * Abstract base class for the results of a Transaction.
+ */
+class ResultSet {
+  class iterator;
+
+public:
+  virtual ~ResultSet() = default;
+  [[nodiscard]] virtual auto size() const noexcept -> int = 0;
+  [[nodiscard]] virtual auto at(const int index) const -> const Entity & = 0;
+  [[nodiscard]] virtual auto mutable_at(int index) const -> Entity * = 0;
+  /**
+   * Return the Entity at the given index.
+   *
+   * This method releases the entity from the underlying collection and thus
+   * leaves the ResultSet in a corrupted state.
+   *
+   * This method can be called only once for each index.
+   */
+  [[nodiscard]] virtual auto release_at(int index) -> Entity * = 0;
+  auto begin() const -> iterator;
+  auto end() const -> iterator;
+
+private:
+  class iterator : public std::iterator<std::output_iterator_tag, Entity> {
+  public:
+    explicit iterator(const ResultSet *result_set, int index = 0);
+    auto operator*() const -> const Entity &;
+    auto operator++() -> iterator &;
+    auto operator++(int) -> iterator;
+    auto operator!=(const iterator &rhs) const -> bool;
+
+  private:
+    int current_index = 0;
+    const ResultSet *result_set;
+  };
+};
+
+class AbstractMultiResultSet : public ResultSet {
+public:
+  /**
+   * Copy Constructor.
+   *
+   * Copies the underlying collection of entities.
+   */
+  inline AbstractMultiResultSet(const AbstractMultiResultSet &original) {
+    for (const Entity &entity : original) {
+      this->items.push_back(std::make_unique<Entity>(entity));
+    }
+  }
+  virtual ~AbstractMultiResultSet() = default;
+  inline explicit AbstractMultiResultSet(std::vector<std::unique_ptr<Entity>> result_set)
+    : items(std::move(result_set)) {}
+  [[nodiscard]] inline auto size() const noexcept -> int override { return this->items.size(); }
+  [[nodiscard]] inline auto at(const int index) const -> const Entity & override {
+    return *(this->items.at(index));
+  }
+  [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override {
+    return this->items.at(index).get();
+  }
+  /**
+   * Return the Entity at the given index.
+   *
+   * This method releases the entity from the underlying collection and thus
+   * leaves the ResultSet in a corrupted state.
+   *
+   * This method can be called only once for each index.
+   */
+  [[nodiscard]] inline auto release_at(int index) -> Entity * override {
+    return this->items.at(index).release();
+  }
+  /**
+   * Remove all entities from this result set.
+   */
+  inline auto clear() noexcept -> void { this->items.clear(); }
+
+protected:
+  std::vector<std::unique_ptr<Entity>> items;
+};
+
+/**
+ * Container with results of a transaction.
+ */
+class MultiResultSet : public AbstractMultiResultSet {
+public:
+  ~MultiResultSet() = default;
+  explicit MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set);
+};
+
+} // namespace caosdb::transaction
+#endif
diff --git a/include/caosdb/result_table.h b/include/caosdb/result_table.h
index 393924ca94f3f10499c9028fa13f699d583315f0..6795e27e5b60a680c1700d9fa98bcdd50b059474 100644
--- a/include/caosdb/result_table.h
+++ b/include/caosdb/result_table.h
@@ -21,10 +21,10 @@
 #ifndef CAOSDB_RESULT_TABLE_H
 #define CAOSDB_RESULT_TABLE_H
 
-#include "caosdb/value.h"                   // for Value
-#include <iterator>                         // for iterator, next
-#include <memory>  // for unique_ptr
-#include <string>  // for string
+#include "caosdb/value.h" // for Value
+#include <iterator>       // for iterator, next
+#include <memory>         // for unique_ptr
+#include <string>         // for string
 
 namespace caosdb::transaction {
 using caosdb::entity::Value;
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 19c3a97dacc2385eef17965935bce88d9c1088c2..3a635560eef18bea425dff2c62dca100b782d0b7 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -30,22 +30,20 @@
 #include "caosdb/logging.h"                 // for CAOSDB_LOG_ERR...
 #include "caosdb/protobuf_helper.h"         // for get_arena
 #include "caosdb/status_code.h"             // for StatusCode
+#include "caosdb/result_set.h"              // for ResultSet
 #include "caosdb/result_table.h"            // for ResultTable
 #include "caosdb/transaction_status.h"      // for StatusCode
 #include "caosdb/value.h"                   // for Value
-#include <algorithm>                        // for max
 #include <future>                           // for async, future
 #include <google/protobuf/arena.h>          // for Arena
 #include <google/protobuf/util/json_util.h> // for MessageToJsonS...
 #include <grpcpp/completion_queue.h>        // for CompletionQueue
 #include <iterator>                         // for iterator, next
 #include <map>                              // for map
-// IWYU pragma: no_include <ext/alloc_traits.h>
-#include <memory>  // for unique_ptr
-#include <mutex>   // for mutex
-#include <string>  // for string
-#include <utility> // for move
-#include <vector>  // for vector
+#include <memory>                           // for unique_ptr
+#include <mutex>                            // for mutex
+#include <string>                           // for string
+#include <vector>                           // for vector
 
 /**
  * Do all necessary checks and assure that another retrieval (by id or by
@@ -190,95 +188,6 @@ using google::protobuf::Arena;
 
 class Transaction;
 
-/**
- * Abstract base class for the results of a Transaction.
- */
-class ResultSet {
-  class iterator;
-
-public:
-  virtual ~ResultSet() = default;
-  [[nodiscard]] virtual auto size() const noexcept -> int = 0;
-  [[nodiscard]] virtual auto at(const int index) const -> const Entity & = 0;
-  [[nodiscard]] virtual auto mutable_at(int index) const -> Entity * = 0;
-  /**
-   * Return the Entity at the given index.
-   *
-   * This method releases the entity from the underlying collection and thus
-   * leaves the ResultSet in a corrupted state.
-   *
-   * This method can be called only once for each index.
-   */
-  [[nodiscard]] virtual auto release_at(int index) -> Entity * = 0;
-  auto begin() const -> iterator;
-  auto end() const -> iterator;
-
-private:
-  class iterator : public std::iterator<std::output_iterator_tag, Entity> {
-  public:
-    explicit iterator(const ResultSet *result_set, int index = 0);
-    auto operator*() const -> const Entity &;
-    auto operator++() -> iterator &;
-    auto operator++(int) -> iterator;
-    auto operator!=(const iterator &rhs) const -> bool;
-
-  private:
-    int current_index = 0;
-    const ResultSet *result_set;
-  };
-};
-
-class AbstractMultiResultSet : public ResultSet {
-public:
-  /**
-   * Copy Constructor.
-   *
-   * Copies the underlying collection of entities.
-   */
-  inline AbstractMultiResultSet(const AbstractMultiResultSet &original) {
-    for (const Entity &entity : original) {
-      this->items.push_back(std::make_unique<Entity>(entity));
-    }
-  }
-  virtual ~AbstractMultiResultSet() = default;
-  inline explicit AbstractMultiResultSet(std::vector<std::unique_ptr<Entity>> result_set)
-    : items(std::move(result_set)) {}
-  [[nodiscard]] inline auto size() const noexcept -> int override { return this->items.size(); }
-  [[nodiscard]] inline auto at(const int index) const -> const Entity & override {
-    return *(this->items.at(index));
-  }
-  [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override {
-    return this->items.at(index).get();
-  }
-  /**
-   * Return the Entity at the given index.
-   *
-   * This method releases the entity from the underlying collection and thus
-   * leaves the ResultSet in a corrupted state.
-   *
-   * This method can be called only once for each index.
-   */
-  [[nodiscard]] inline auto release_at(int index) -> Entity * override {
-    return this->items.at(index).release();
-  }
-  /**
-   * Remove all entities from this result set.
-   */
-  inline auto clear() noexcept -> void { this->items.clear(); }
-
-protected:
-  std::vector<std::unique_ptr<Entity>> items;
-};
-
-/**
- * Container with results of a transaction.
- */
-class MultiResultSet : public AbstractMultiResultSet {
-public:
-  ~MultiResultSet() = default;
-  explicit MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set);
-};
-
 /**
  * @brief Create a transaction via `CaosDBConnection.createTransaction()`
  */
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index c89bd226bbc618b46d985eb087c540d1c1f35e56..cffb11162b9ed8b83508316c155f1fca46be2714 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -52,14 +52,6 @@ using ScalarValueCase = caosdb::entity::v1::ScalarValue::ScalarValueCase;
 class ScalarValue;
 class Value;
 
-// Represents special values which are otherwise hard to tranfer via protobuf.
-enum SpecialValue {
-  // Represent the NULL value.
-  NULL_VALUE = ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED,
-  // The empty string.
-  EMPTY_STRING = ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING,
-};
-
 /**
  * Pure abstract base class for values.
  */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b4f28930ce2402c2c3a7ea03c994b8a07e492a58..939a85ba1f0492a6d985d4f873f2560adb22f039 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,6 +27,7 @@ set(libcaosdb_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/connection.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/configuration.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_set.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table_impl.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.cpp
diff --git a/src/caosdb/result_set.cpp b/src/caosdb/result_set.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a4172a836d4e8bb9ed5e568439556ebace53c4e4
--- /dev/null
+++ b/src/caosdb/result_set.cpp
@@ -0,0 +1,55 @@
+/*
+ * This file is a part of the CaosDB Project.
+ * Copyright (C) 2021-2022 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021-2022 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
+ * 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/>.
+ *
+ */
+#include "caosdb/result_set.h" // for ResultSet
+#include <memory>              // for unique_ptr
+#include <utility>             // for move, pair
+
+namespace caosdb::transaction {
+
+ResultSet::iterator::iterator(const ResultSet *result_set_param, int index)
+  : current_index(index), result_set(result_set_param) {}
+
+auto ResultSet::iterator::operator*() const -> const Entity & {
+  return this->result_set->at(current_index);
+}
+
+auto ResultSet::iterator::operator++() -> ResultSet::iterator & {
+  current_index++;
+  return *this;
+}
+
+auto ResultSet::iterator::operator++(int) -> ResultSet::iterator {
+  iterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+auto ResultSet::iterator::operator!=(const iterator &rhs) const -> bool {
+  return this->current_index != rhs.current_index;
+}
+
+auto ResultSet::begin() const -> ResultSet::iterator { return ResultSet::iterator(this, 0); }
+
+auto ResultSet::end() const -> ResultSet::iterator { return ResultSet::iterator(this, size()); }
+
+MultiResultSet::MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set)
+  : AbstractMultiResultSet(std::move(result_set)) {}
+
+} // namespace caosdb::transaction
diff --git a/src/caosdb/result_table.cpp b/src/caosdb/result_table.cpp
index f6fa223bbde47d64944d3fd1aa464beb01dc3e56..f7d5c3e3564fdad9b7f9755c77c6ddce37d3c25f 100644
--- a/src/caosdb/result_table.cpp
+++ b/src/caosdb/result_table.cpp
@@ -18,17 +18,17 @@
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  *
  */
-#include "caosdb/result_table.h"               // for ResultTable, ResultTab...
-#include "caosdb/entity/v1/main.pb.h"          // for SelectQueryResult, Sel...
-#include "caosdb/protobuf_helper.h"            // for ScalarProtoMessageWrapper
-#include "caosdb/result_table_impl.h"          // for ResultTableImpl, Resul...
-#include "caosdb/value.h"                      // for Value
-#include <algorithm>                           // for max
+#include "caosdb/result_table.h"            // for ResultTable, ResultTab...
+#include "caosdb/entity/v1/main.pb.h"       // for SelectQueryResult, Sel...
+#include "caosdb/protobuf_helper.h"         // for ScalarProtoMessageWrapper
+#include "caosdb/result_table_impl.h"       // for ResultTableImpl, Resul...
+#include "caosdb/value.h"                   // for Value
+#include <algorithm>                        // for max
 #include <google/protobuf/repeated_field.h> // IWYU pragma: keep for RepeatedPtrField
-#include <memory>                              // for unique_ptr
-#include <string>                              // for string, operator==
-#include <utility>                             // for move
-#include <vector>                              // for vector
+#include <memory>                           // for unique_ptr
+#include <string>                           // for string, operator==
+#include <utility>                          // for move
+#include <vector>                           // for vector
 // IWYU pragma: no_include "net/proto2/public/repeated_field.h"
 
 namespace caosdb::transaction {
@@ -140,9 +140,7 @@ auto ResultTable::RowIterator::end() const -> RowIterator {
   return RowIterator(this->result_table, size());
 }
 
-auto ResultTable::GetHeader() const noexcept -> HeaderIterator {
-  return HeaderIterator(this, 0);
-}
+auto ResultTable::GetHeader() const noexcept -> HeaderIterator { return HeaderIterator(this, 0); }
 
 ResultTable::HeaderIterator::HeaderIterator(const ResultTable *result_table_param, int index)
   : current_index(index), result_table(result_table_param) {}
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 5ea5496fc46e807f2be63057ae2aa0efed9f00ae..28f9e35fc1a70083d07c99e7f8a4fabfbe58bc32 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -26,6 +26,7 @@
 #include "caosdb/file_transmission/upload_request_handler.h"       // Upload...
 #include "caosdb/logging.h"                                        // for CAOSDB_LOG_FATAL
 #include "caosdb/protobuf_helper.h"                                // for ProtoMessageWrapper
+#include "caosdb/result_set.h"                                     // for ResultSet
 #include "caosdb/result_table.h"                                   // for ResultTable
 #include "caosdb/result_table_impl.h"                              // for ResultTableImpl
 #include "caosdb/status_code.h"                                    // for StatusCode
@@ -41,7 +42,6 @@
 #include <random>                                                  // for mt19937, rand...
 #include <system_error>                                            // for std::system_error
 #include <utility>                                                 // for move, pair
-// IWYU pragma: no_include <bits/exception.h>
 // IWYU pragma: no_include <cxxabi.h>
 // IWYU pragma: no_include "net/proto2/public/repeated_field.h"
 
@@ -61,35 +61,6 @@ using google::protobuf::Arena;
 using NextStatus = grpc::CompletionQueue::NextStatus;
 using RegistrationStatus = caosdb::entity::v1::RegistrationStatus;
 
-ResultSet::iterator::iterator(const ResultSet *result_set_param, int index)
-  : current_index(index), result_set(result_set_param) {}
-
-auto ResultSet::iterator::operator*() const -> const Entity & {
-  return this->result_set->at(current_index);
-}
-
-auto ResultSet::iterator::operator++() -> ResultSet::iterator & {
-  current_index++;
-  return *this;
-}
-
-auto ResultSet::iterator::operator++(int) -> ResultSet::iterator {
-  iterator tmp(*this);
-  operator++();
-  return tmp;
-}
-
-auto ResultSet::iterator::operator!=(const iterator &rhs) const -> bool {
-  return this->current_index != rhs.current_index;
-}
-
-auto ResultSet::begin() const -> ResultSet::iterator { return ResultSet::iterator(this, 0); }
-
-auto ResultSet::end() const -> ResultSet::iterator { return ResultSet::iterator(this, size()); }
-
-MultiResultSet::MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set)
-  : AbstractMultiResultSet(std::move(result_set)) {}
-
 Transaction::Transaction(std::shared_ptr<EntityTransactionService::Stub> entity_service,
                          std::shared_ptr<FileTransmissionService::Stub> file_service)
   : entity_service(std::move(entity_service)), file_service(std::move(file_service)),
diff --git a/test/test_issues.cpp b/test/test_issues.cpp
index b7a6cc8fe7df2bbcf8b2db0902c57c7146b77faf..6422da5f4c86128be44286d853d768cd58db3c8c 100644
--- a/test/test_issues.cpp
+++ b/test/test_issues.cpp
@@ -19,6 +19,7 @@
  */
 #include "caosdb/configuration.h"      // for InsecureConnectionConfig...
 #include "caosdb/connection.h"         // for Connection
+#include "caosdb/result_set.h"         // for ResultSet
 #include "caosdb/status_code.h"        // for StatusCode, EXECUTING
 #include "caosdb/transaction.h"        // for Transaction
 #include "caosdb/transaction_status.h" // for StatusCode
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index 77d457c6eee2c5e9d95c53c95c1b2f0a713dcff4..ed4dcd2aa72e3e857bc871f401504147b330385b 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -22,6 +22,7 @@
 #include "caosdb/entity.h"              // for Entity
 #include "caosdb/entity/v1/main.pb.h"   // for Entity
 #include "caosdb/exceptions.h"          // for ConnectionError
+#include "caosdb/result_set.h"          // for MultiResultSet, Entity, Resu...
 #include "caosdb/status_code.h"         // for StatusCode
 #include "caosdb/transaction.h"         // for Transaction
 #include "caosdb/transaction_handler.h" // for MultiTransactionResponse