diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95bc1767adf29ed2619a5a817aac2a4b1b4c6870..eb3340b0a9e3f8fe4786f3cd497c10edf225510b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -159,7 +159,8 @@ if(_LINTING)
         message(WARNING "include-what-you-use: Not found")
     else()
         message(STATUS "include-what-you-use: ${iwyu}")
-        set(_CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${iwyu} "-Xiwyu" "--cxx17ns")
+        set(_CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${iwyu}
+            "-Xiwyu" "--cxx17ns" "-Xiwyu" "--no_fwd_decls")
 
         set_target_properties(caosdb PROPERTIES
             CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
diff --git a/include/caosdb/authentication.h b/include/caosdb/authentication.h
index da004572cf96432fae3a57350b312f23f43b319c..d8c3595ddb8a89be2a4d0011d37d6e7fc4a480ee 100644
--- a/include/caosdb/authentication.h
+++ b/include/caosdb/authentication.h
@@ -28,16 +28,15 @@
  * @brief Configuration and setup of the client authentication.
  */
 
-#include <grpcpp/security/credentials.h>    // for MetadataCredentialsPlugin
-#include <map>                              // for multimap
-#include <memory>                           // for shared_ptr
-#include <string>                           // for string
-#include "caosdb/utils.h"                   // for base64_encode
-#include "grpcpp/impl/codegen/status.h"     // for Status
-#include "grpcpp/impl/codegen/string_ref.h" // for string_ref
-namespace grpc {
-class AuthContext;
-}
+#include <grpcpp/security/credentials.h>               // for CallCredentials
+#include <map>                                         // for multimap
+#include <memory>                                      // for shared_ptr
+#include <string>                                      // for string
+#include "caosdb/utils.h"                              // for base64_encode
+#include "grpcpp/impl/codegen/interceptor.h"           // for Status
+#include "grpcpp/impl/codegen/security/auth_context.h" // for AuthContext
+#include "grpcpp/impl/codegen/status.h"                // for Status
+#include "grpcpp/impl/codegen/string_ref.h"            // for string_ref
 
 namespace caosdb {
 namespace authentication {
diff --git a/include/caosdb/connection.h b/include/caosdb/connection.h
index b3350dfac17cf54176c62a1ef53e50b4e7e2bc80..0e722a512b22bbd18fdb18f3fcecaeeb7a0a64a7 100644
--- a/include/caosdb/connection.h
+++ b/include/caosdb/connection.h
@@ -27,23 +27,20 @@
  * @date 2021-05-18
  * @brief Configuration and setup of the connection.
  */
-#include <iosfwd> // for ostream
-#include <memory> // for shared_ptr, unique_ptr
-#include <string> // for string
-#include "caosdb/transaction.h"
-#include "caosdb/info/v1alpha1/main.grpc.pb.h"   // for GeneralInfoService
-#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionService
-
-namespace caosdb {
-namespace authentication {
+#include <iosfwd>                                // for ostream
+#include <memory>                                // for shared_ptr, unique_ptr
+#include <string>                                // for string
+#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
+#include "caosdb/info/v1alpha1/main.grpc.pb.h"   // for GeneralInfoService:...
+#include "caosdb/transaction.h"                  // for Transaction
+#include "grpcpp/impl/codegen/client_callback.h" // for Channel
+namespace caosdb::authentication {
 class Authenticator;
-} // namespace authentication
-namespace info {
+} // namespace caosdb::authentication
+namespace caosdb::info {
 class VersionInfo;
-} // namespace info
-} // namespace caosdb
+} // namespace caosdb::info
 namespace grpc {
-class Channel;
 class ChannelCredentials;
 } // namespace grpc
 
diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index 1c22f9cc2bd59d192100236e78ed92fe83786582..e98b852ea0ca63758ed0e9bd68cf039d0f728d1a 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -28,10 +28,9 @@
 #ifndef CAOSDB_ENTITY_H
 #define CAOSDB_ENTITY_H
 
-#include <memory> // for shared_ptr
-#include <string> // for string
-#include <google/protobuf/repeated_field.h>
-#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity
+#include <memory>                           // for unique_ptr
+#include <string>                           // for string
+#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity, RepeatedField
 
 namespace caosdb::entity {
 
@@ -122,17 +121,29 @@ public:
       parents(
         (::google::protobuf::RepeatedField<caosdb::entity::v1alpha1::Parent> *)
           wrapped->mutable_parents()){};
-  [[nodiscard]] auto GetId() const -> const std::string &;
-  [[nodiscard]] auto GetVersion() const -> const std::string &;
-
-  [[nodiscard]] auto GetRole() const -> const std::string &;
-  [[nodiscard]] auto GetName() const -> const std::string &;
+  [[nodiscard]] inline auto GetId() const -> const std::string & {
+    return wrapped->id();
+  };
+  [[nodiscard]] inline auto GetVersion() const -> const std::string & {
+    return wrapped->version().id();
+  };
+
+  [[nodiscard]] inline auto GetRole() const -> const std::string & {
+    return wrapped->role();
+  };
+  [[nodiscard]] inline auto GetName() const -> const std::string & {
+    return wrapped->name();
+  };
   [[nodiscard]] inline auto GetDescription() const -> const std::string & {
     return wrapped->description();
-  }
-
-  [[nodiscard]] auto GetDatatype() const -> const std::string &;
-  [[nodiscard]] auto GetUnit() const -> const std::string &;
+  };
+
+  [[nodiscard]] auto GetDatatype() const -> const std::string & {
+    return wrapped->datatype();
+  };
+  [[nodiscard]] auto GetUnit() const -> const std::string & {
+    return wrapped->unit();
+  };
 
   [[nodiscard]] auto GetParents() const -> const Parents &;
   [[nodiscard]] auto GetProperties() const -> const Properties &;
diff --git a/include/caosdb/info.h b/include/caosdb/info.h
index e5961cd862c2dd3bc469e23bdaf4b0278e9a2980..f4f290b1ebde4a5ef89aaf8ecef9017b822296ba 100644
--- a/include/caosdb/info.h
+++ b/include/caosdb/info.h
@@ -36,19 +36,43 @@ namespace caosdb::info {
 using ProtoVersionInfo = caosdb::info::v1alpha1::VersionInfo;
 
 /**
- * @brief Wrapper class for the VersionInfo protobuf.
+ * A read-only version object which represents the version of the server.
+ *
+ * The version info follows semantic versioning (SemVer 2.0). Wrapper class for
+ * the VersionInfo protobuf.
+ *
+ * @brief A read-only version object which represents the version of the server.
  */
 class VersionInfo {
-private:
-  ProtoVersionInfo *info;
-
 public:
-  explicit VersionInfo(ProtoVersionInfo *info);
-  [[nodiscard]] auto GetMajor() const -> uint32_t;
-  [[nodiscard]] auto GetMinor() const -> uint32_t;
-  [[nodiscard]] auto GetPatch() const -> uint32_t;
-  [[nodiscard]] auto GetPreRelease() const -> const std::string &;
-  [[nodiscard]] auto GetBuild() const -> const std::string &;
+  /**
+   * Wrapp a Protobuf VersionInfo object.
+   *
+   * Don't instantiate this version info class. The constructor is only public
+   * for simpler testing. Create a CaosDBConnection and use
+   * CaosDBConnection::GetVersionInfo() instead to get the version of the
+   * server behind the given connection.
+   */
+  explicit inline VersionInfo(ProtoVersionInfo *info) : info(info){};
+  [[nodiscard]] inline auto GetMajor() const -> uint32_t {
+    return this->info->major();
+  }
+  [[nodiscard]] inline auto GetMinor() const -> uint32_t {
+    return this->info->minor();
+  }
+  [[nodiscard]] inline auto GetPatch() const -> uint32_t {
+    return this->info->patch();
+  }
+  [[nodiscard]] inline auto GetPreRelease() const -> const std::string & {
+    return this->info->pre_release();
+  }
+  [[nodiscard]] inline auto GetBuild() const -> const std::string & {
+    return this->info->build();
+  }
+
+private:
+  /// This object is the owner of the Protobuf VersionInfo message.
+  std::unique_ptr<ProtoVersionInfo> info;
 };
 
 } // namespace caosdb::info
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 9333957bd1dcf25957b9b2df75a826113e3001ac..8989951997a9da6bb821dec9e55345bbbb0c72b9 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -26,10 +26,11 @@
 #ifndef CAOSDB_TRANSACTION_H
 #define CAOSDB_TRANSACTION_H
 
-#include <memory>
-#include "caosdb/entity.h"
-#include "caosdb/entity/v1alpha1/main.pb.h"
-#include "caosdb/entity/v1alpha1/main.grpc.pb.h"
+#include <memory>                                // for shared_ptr, unique_ptr
+#include <string>                                // for string
+#include "caosdb/entity.h"                       // for Entity
+#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
+#include "caosdb/entity/v1alpha1/main.pb.h"      // for Entity, RetrieveReq...
 
 namespace caosdb::transaction {
 using caosdb::entity::Entity;
@@ -37,16 +38,20 @@ using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using caosdb::entity::v1alpha1::EntityTransactionService;
 using caosdb::entity::v1alpha1::RetrieveRequest;
 
-class ResultSet {};
+class ResultSet {
+public:
+  virtual ~ResultSet(){};
+};
 
 class UniqueResult : public ResultSet {
-private:
-  std::unique_ptr<Entity> entity;
-
 public:
+  ~UniqueResult(){};
   explicit inline UniqueResult(ProtoEntity *protoEntity)
     : entity(new Entity(protoEntity)){};
   [[nodiscard]] auto GetEntity() const -> const Entity &;
+
+private:
+  std::unique_ptr<Entity> entity;
 };
 
 enum TransactionState { INIT = 10, EXECUTING = 20, SUCCESS = 30, ERROR = 40 };
@@ -56,7 +61,7 @@ enum TransactionState { INIT = 10, EXECUTING = 20, SUCCESS = 30, ERROR = 40 };
  */
 class Transaction {
 private:
-  std::shared_ptr<ResultSet> result_set;
+  std::unique_ptr<ResultSet> result_set;
   TransactionState state = TransactionState::INIT;
   std::shared_ptr<EntityTransactionService::Stub> service_stub;
   RetrieveRequest request; // TODO(tf)
@@ -65,8 +70,10 @@ public:
   Transaction(std::shared_ptr<EntityTransactionService::Stub> service_stub);
   auto RetrieveById(const std::string &id) -> void;
   auto Execute() -> void;
-  [[nodiscard]] auto GetResultSet() const -> std::shared_ptr<ResultSet>;
-  auto WaitForIt() const -> void;
+  [[nodiscard]] inline auto GetResultSet() const -> const ResultSet & {
+    const ResultSet *result_set = this->result_set.get();
+    return *result_set;
+  }
 };
 
 } // namespace caosdb::transaction
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2ea6daa9136baffb1662dc2fe95aefe382265c62..eeabe29cce0d81e5515bd5510584502282e0dd1d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -23,8 +23,6 @@
 set(libcaosdb_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/authentication.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/connection.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/entity.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/info.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.cpp
     )
 
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
deleted file mode 100644
index b39623a38e9a3883f5b16aa858c0f787cfa46704..0000000000000000000000000000000000000000
--- a/src/caosdb/entity.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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/>.
- *
- */
-
-#include "caosdb/entity.h"
-#include <utility>
-
-namespace caosdb::entity {} // namespace caosdb::entity
diff --git a/src/caosdb/info.cpp b/src/caosdb/info.cpp
index b492dade80118abd331019adc5272511c50266d1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/src/caosdb/info.cpp
+++ b/src/caosdb/info.cpp
@@ -1,50 +0,0 @@
-/*
- * 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/>.
- *
- */
-
-#include "caosdb/info.h"
-#include "caosdb/info/v1alpha1/main.pb.h" // for GetVersionInfoResponse
-
-namespace caosdb::info {
-using ProtoVersionInfo = caosdb::info::v1alpha1::VersionInfo;
-
-VersionInfo::VersionInfo(ProtoVersionInfo *info) { this->info = info; }
-
-[[nodiscard]] auto VersionInfo::GetMajor() const -> uint32_t {
-  return this->info->major();
-}
-
-[[nodiscard]] auto VersionInfo::GetMinor() const -> uint32_t {
-  return this->info->minor();
-}
-
-[[nodiscard]] auto VersionInfo::GetPatch() const -> uint32_t {
-  return this->info->patch();
-}
-
-[[nodiscard]] auto VersionInfo::GetPreRelease() const -> const std::string & {
-  return this->info->pre_release();
-}
-
-[[nodiscard]] auto VersionInfo::GetBuild() const -> const std::string & {
-  return this->info->build();
-}
-
-} // namespace caosdb::info
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 60713c5a758b08ded0797e5f6ddb4b7e001b4191..bf2e88411fa15fd94f7b1ca4a1546c1bc23e2b90 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -51,6 +51,7 @@ Transaction::Transaction(
 
 auto Transaction::RetrieveById(const std::string &id) -> void {
   RetrieveRequest request;
+  // this copies the id, so we're safe.
   request.mutable_by_id()->set_id(id);
 
   this->request = request;
@@ -78,18 +79,8 @@ auto Transaction::Execute() -> void {
   }
 
   auto *entity = response.release_entity();
-  auto result_set = std::make_shared<UniqueResult>(entity);
-  this->result_set = result_set;
-}
-
-auto Transaction::WaitForIt() const -> void {
-  // TODO(tf) throw error if still in INIT state
-  // TODO(tf)
-}
-
-[[nodiscard]] auto Transaction::GetResultSet() const
-  -> std::shared_ptr<ResultSet> {
-  return this->result_set;
+  auto result_set = std::make_unique<UniqueResult>(entity);
+  this->result_set = std::move(result_set);
 }
 
 } // namespace caosdb::transaction
diff --git a/src/caosdbcli.cpp b/src/caosdbcli.cpp
index 26d86d620e092b2aa593b91be4f514053514fc9a..a128887ef7acc5004c60ffba4dbb9da2033f95ae 100644
--- a/src/caosdbcli.cpp
+++ b/src/caosdbcli.cpp
@@ -71,12 +71,13 @@ auto main() -> int {
   auto transaction(connection.CreateTransaction());
   transaction->RetrieveById("20");
   transaction->Execute();
-  auto result_set(std::static_pointer_cast<caosdb::transaction::UniqueResult>(
-    transaction->GetResultSet()));
+  const auto &result_set =
+    dynamic_cast<const caosdb::transaction::UniqueResult &>(
+      transaction->GetResultSet());
 
   // print description
-  std::cout << "Entity Description: "
-            << result_set->GetEntity().GetDescription() << std::endl;
+  std::cout << "Entity Description: " << result_set.GetEntity().GetDescription()
+            << std::endl;
 
   return 0;
 }
diff --git a/test/test_connection.cpp b/test/test_connection.cpp
index 6ae9f0f2fd8730187d46a7a34ed5b09824419401..34abc0e4493cd6223339d30d2dba541b5530ea8c 100644
--- a/test/test_connection.cpp
+++ b/test/test_connection.cpp
@@ -25,9 +25,6 @@
 #include <memory>                  // for allocator, operator!=, shared_ptr
 #include "caosdb/connection.h"     // for PemCACertProvider, InsecureCaosDB...
 #include "gtest/gtest_pred_impl.h" // for Test, AssertionResult, EXPECT_EQ
-namespace grpc {
-class ChannelCredentials;
-} // namespace grpc
 
 namespace caosdb::connection {
 
diff --git a/test/test_info.cpp b/test/test_info.cpp
index 9b503e46e8967395b94bf633e3423147b18eaff3..2a806a63ac9fcc8a3c3a9bb8b8cdf582e63cf3d1 100644
--- a/test/test_info.cpp
+++ b/test/test_info.cpp
@@ -33,15 +33,17 @@ using ProtoVersionInfo = caosdb::info::v1alpha1::VersionInfo;
 TEST(test_info, create_info_from_proto_info) {
   auto *origial = new ProtoVersionInfo();
   origial->set_major(12);
+  origial->set_patch(56);
   origial->set_pre_release("SNAPSHOT");
+  origial->set_build("1234asdf");
 
   VersionInfo wrapper(origial);
 
   EXPECT_EQ(12, wrapper.GetMajor());
+  EXPECT_EQ(0, wrapper.GetMinor()); // default value.
+  EXPECT_EQ(56, wrapper.GetPatch());
   EXPECT_EQ("SNAPSHOT", wrapper.GetPreRelease());
-
-  // default value.
-  EXPECT_EQ(0, wrapper.GetMinor());
+  EXPECT_EQ("1234asdf", wrapper.GetBuild());
 }
 
 } // namespace caosdb::info
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index 6c4192550b4ff5a68474c3fed95b5728397514af..4dcc1378193f33032757463aa85bdbaef968346c 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -20,20 +20,23 @@
  *
  */
 
-#include <memory>                  // for allocator, make_shared, unique_ptr
-#include "caosdb/connection.h"     // for InsecureCaosDBConnectionConfig
-#include "caosdb/entity.h"         // for EntityID
-#include "caosdb/exceptions.h"     // for ConnectionError
-#include "caosdb/transaction.h"    // for Transaction, EntityID
-#include "gtest/gtest-message.h"   // for Message
-#include "gtest/gtest-test-part.h" // for TestPartResult
-#include "gtest/gtest.h"           // for Test, SuiteApiResolver, TestInfo ...
-#include "caosdb_test_utility.h"   // for EXPECT_THROW_MESSAGE
+#include <memory>                           // for allocator, make_shared
+#include "caosdb/connection.h"              // for InsecureCaosDBConnection...
+#include "caosdb/entity.h"                  // for Entity
+#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity
+#include "caosdb/exceptions.h"              // for ConnectionError
+#include "caosdb/transaction.h"             // for Transaction, UniqueResult
+#include "caosdb_test_utility.h"            // for EXPECT_THROW_MESSAGE
+#include "gtest/gtest-message.h"            // for Message
+#include "gtest/gtest-test-part.h"          // for SuiteApiResolver, TestPa...
+#include "gtest/gtest_pred_impl.h"          // for Test, TestInfo, TEST
 
 namespace caosdb::transaction {
 using caosdb::connection::CaosDBConnection;
 using caosdb::connection::InsecureCaosDBConnectionConfig;
 using caosdb::exceptions::ConnectionError;
+using caosdb::transaction::UniqueResult;
+using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 
 TEST(test_transaction, create_transaction) {
   const auto *pHost = "localhost";
@@ -41,9 +44,21 @@ TEST(test_transaction, create_transaction) {
   CaosDBConnection connection(config);
   auto transaction = connection.CreateTransaction();
 
-  transaction->Retrieve(EntityID("someid"));
+  transaction->RetrieveById("100");
   EXPECT_THROW_MESSAGE(transaction->Execute(), ConnectionError,
                        "failed to connect to all addresses");
 }
 
+TEST(test_transaction, unique_result) {
+  auto *entity = new ProtoEntity();
+  entity->set_id("test");
+  UniqueResult result(entity);
+
+  EXPECT_EQ("test", result.GetEntity().GetId());
+
+  // DON'T DELETE! The caosdb::entity::Entity takes care of that
+  // Try it yourself:
+  // delete entity;
+}
+
 } // namespace caosdb::transaction