From d2b59b64d6204b7105101947090fe002b3fb97e4 Mon Sep 17 00:00:00 2001
From: Petar Hristov <hristov@itc.rwth-aachen.de>
Date: Fri, 12 Jan 2024 13:48:32 +0100
Subject: [PATCH] BREAKING: Migrated SQL2Linked to the APIv2 infrastructure

---
 .../Implementations/ProjectStructuralData.cs  | 261 ++++++++--------
 .../Implementations/ResourceStructuralData.cs | 267 ++++++++--------
 .../ResourceTypeStructuralData.cs             | 134 +++++---
 .../Implementations/RoleStructuralData.cs     | 117 ++++---
 .../Implementations/UserStructuralData.cs     |  92 +++---
 .../ConfigurationModels/PidConfiguration.cs   |  17 ++
 .../SQL2LinkedConfiguration.cs                |  17 ++
 src/SQL2Linked/Program.cs                     | 107 +++++--
 src/SQL2Linked/SQL2Linked.csproj              |  33 +-
 src/SQL2Linked/StructuralData.cs              | 288 +++++++++---------
 src/SQL2Linked/Utils/RdfUris.cs               | 215 +++++++++++++
 src/SQL2Linked/Utils/UriHelper.cs             |  31 ++
 src/SQL2Linked/WrapperGraph.cs                |  40 ---
 13 files changed, 997 insertions(+), 622 deletions(-)
 create mode 100644 src/SQL2Linked/Models/ConfigurationModels/PidConfiguration.cs
 create mode 100644 src/SQL2Linked/Models/ConfigurationModels/SQL2LinkedConfiguration.cs
 create mode 100644 src/SQL2Linked/Utils/RdfUris.cs
 create mode 100644 src/SQL2Linked/Utils/UriHelper.cs
 delete mode 100644 src/SQL2Linked/WrapperGraph.cs

diff --git a/src/SQL2Linked/Implementations/ProjectStructuralData.cs b/src/SQL2Linked/Implementations/ProjectStructuralData.cs
index 876f9db..b50b0b1 100644
--- a/src/SQL2Linked/Implementations/ProjectStructuralData.cs
+++ b/src/SQL2Linked/Implementations/ProjectStructuralData.cs
@@ -1,179 +1,166 @@
-using Coscine.Database.DataModel;
-using Coscine.Database.Models;
-using Coscine.Database.Util;
+using Coscine.ApiClient;
+using Coscine.ApiClient.Core.Model;
+using SQL2Linked.Utils;
 using VDS.RDF;
 
-namespace SQL2Linked.Implementations
+namespace SQL2Linked.Implementations;
+
+/// <summary>
+/// Class responsible for converting project data into linked data graphs.
+/// It retrieves project information from the API and then transforms this data into a series of RDF graphs,
+/// making use of predefined URIs and RDF constructs.
+/// </summary>
+public class ProjectStructuralData : StructuralData<ProjectAdminDto>
 {
-    public class ProjectStructuralData : StructuralData<Project, ProjectModel>
+    /// <summary>
+    /// Asynchronously retrieves all project data, including deleted projects.
+    /// </summary>
+    /// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a collection of <see cref="ProjectAdminDto"/>.</returns>
+    /// <remarks>This override allows for the inclusion of deleted projects.</remarks>
+    public override async Task<IEnumerable<ProjectAdminDto>> GetAll()
     {
-        public readonly Uri org = new("http://www.w3.org/ns/org#");
-        public readonly Uri dcat = new("http://www.w3.org/ns/dcat#");
-        public readonly Uri dcterms = new("http://purl.org/dc/terms/");
-        public readonly Uri foaf = new("http://xmlns.com/foaf/0.1/");
-        public readonly Uri vcard = new("http://www.w3.org/2006/vcard/ns#");
-        public readonly Uri rdf = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
-        public readonly Uri cosc = new("https://purl.org/coscine/");
-
-        private readonly VisibilityModel VisibilityModel = new();
-        private readonly ProjectRoleModel ProjectRoleModel = new();
-        private readonly ProjectResourceModel ProjectResourceModel = new();
-        private readonly ProjectInstituteModel ProjectInstituteModel = new();
-
-        // Override to also receive deleted projects
-        public override IEnumerable<Project> GetAll()
-        {
-            return DatabaseConnection.ConnectToDatabase((db) =>
-            {
-                return
-                    (from tableEntry in Model.GetITableFromDatabase(db)
-                     select tableEntry).ToList();
-            });
-        }
+        return await RequestUtil.WrapPagedRequest<ProjectAdminDtoPagedResponse, ProjectAdminDto>(
+            (currentPage) => _adminApi.GetAllProjectsAsync(includeDeleted: true, pageNumber: currentPage, pageSize: 250)
+        );
+    }
 
-        public override IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<Project> entries)
+    /// <summary>
+    /// Converts a collection of project data entries into a set of RDF graphs.
+    /// Each project is transformed into a graph, with RDF triples representing various properties of the project.
+    /// </summary>
+    /// <param name="entries">A collection of <see cref="ProjectAdminDto"/> instances representing project data.</param>
+    /// <returns>A collection of <see cref="IGraph"/> instances, each representing an RDF graph of a project.</returns>
+    public override async Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<ProjectAdminDto> entries)
+    {
+        var graphs = new List<IGraph>();
+        var coscineHandlePrefix = UriHelper.TryCombineUri(RdfUris.HandlePrefix, _pidConfiguration.Prefix)
+            ?? throw new Exception("Could not combine handle prefix with PID prefix");
+
+        var coscineGraph = new Graph
         {
-            IEnumerable<Visibility> visibilities = VisibilityModel.GetAll();
-            IEnumerable<ProjectRole> projectRoles = ProjectRoleModel.GetAll();
-            IEnumerable<ProjectResource> projectResources = ProjectResourceModel.GetAll();
-            IEnumerable<ProjectInstitute> projectInstitutes = ProjectInstituteModel.GetAll();
+            BaseUri = RdfUris.CoscinePrefix
+        };
+        AssertToGraphUriNode(coscineGraph, RdfUris.CoscinePrefix, RdfUris.DcatCatalog, RdfUris.CoscineProjects);
+        AssertToGraphUriNode(coscineGraph, RdfUris.CoscinePrefix, RdfUris.DcatCatalog, RdfUris.CoscineResources);
+        graphs.Add(coscineGraph);
 
-            var graphs = new List<IGraph>();
-            var projectUrlHandlePrefix = "https://hdl.handle.net/" + Prefix;
-            var projectUrlPrefix = "https://purl.org/coscine/projects";
-            var resourceUrlPrefix = "https://purl.org/coscine/resources";
+        foreach (var entry in entries)
+        {
+            var projectGraphName = UriHelper.TryCombineUri(RdfUris.CoscineProjects, entry.Id)
+                ?? throw new Exception("Could not combine projects prefix with project ID");
+            var projectHandleName = UriHelper.TryCombineUri(coscineHandlePrefix, entry.Id);
 
-            var coscineGraph = new Graph
+            var graph = new Graph
             {
-                BaseUri = cosc
+                BaseUri = projectGraphName
             };
-            AssertToGraphUriNode(coscineGraph, cosc.AbsoluteUri, dcat + "catalog", projectUrlPrefix + "/");
-            AssertToGraphUriNode(coscineGraph, cosc.AbsoluteUri, dcat + "catalog", resourceUrlPrefix + "/");
-            graphs.Add(coscineGraph);
 
-            foreach (var entry in entries)
-            {
-                var projectGraphName = $"{projectUrlPrefix}/{entry.Id}";
-                var projectHandleName = $"{projectUrlHandlePrefix}/{entry.Id}";
-
-                var graph = new Graph
-                {
-                    BaseUri = new Uri(projectGraphName)
-                };
+            AssertToGraphUriNode(graph, projectGraphName, RdfUris.A, RdfUris.DcatCatalogClass);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.A} {RdfUris.DcatCatalogClass}'. ");
 
-                AssertToGraphUriNode(graph, projectGraphName, rdf + "type", dcat + "Catalog");
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {rdf}type {dcat}Catalog'. ");
+            AssertToGraphUriNode(graph, projectGraphName, RdfUris.A, RdfUris.OrgOrganizationalCollaborationClass);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.A} {RdfUris.OrgOrganizationalCollaborationClass}'. ");
 
-                AssertToGraphUriNode(graph, projectGraphName, rdf + "type", org + "OrganizationalCollaboration");
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {rdf}type {org}OrganizationalCollaboration'. ");
+            AssertToGraphUriNode(graph, projectGraphName, RdfUris.A, RdfUris.VcardGroupClass);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.A} {RdfUris.VcardGroupClass}'. ");
 
-                AssertToGraphUriNode(graph, projectGraphName, rdf + "type", vcard + "Group");
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {rdf}type {vcard}Group'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsTitle, entry.Name);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsTitle} {entry.Name}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "title", entry.ProjectName);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}title {entry.ProjectName}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsDescription, entry.Description);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsDescription} {entry.Description}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "description", entry.Description);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}description {entry.Description}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsStartDate, entry.StartDate.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsStartDate} {entry.StartDate}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcat + "startDate", entry.StartDate.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcat}startDate {entry.StartDate}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsEndDate, entry.EndDate.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsEndDate} {entry.EndDate}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcat + "endDate", entry.EndDate.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcat}endDate {entry.EndDate}'. ");
-
-                if (!string.IsNullOrWhiteSpace(entry.Keywords))
+            if (entry.Keywords.Count > 0)
+            {
+                foreach (var keyword in entry.Keywords)
                 {
-                    var listKeywords = entry.Keywords.Split(';').ToList();
-                    foreach (var keyword in listKeywords)
-                    {
-                        AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "subject", keyword);
-                        Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}subject {keyword}'. ");
-                    }
+                    AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsSubject, keyword);
+                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsSubject} {keyword}'. ");
                 }
+            }
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "alternative", entry.DisplayName);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}alternative {entry.DisplayName}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsAlternative, entry.DisplayName);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsAlternative} {entry.DisplayName}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "rightsHolder", entry.PrincipleInvestigators);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}rightsHolder {entry.PrincipleInvestigators}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsRightsHolder, entry.PrincipleInvestigators);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsRightsHolder} {entry.PrincipleInvestigators}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, "https://schema.org/funding", entry.GrantId);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} https://schema.org/funding {entry.GrantId}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.SchemaFunding, entry.GrantId);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.SchemaFunding} {entry.GrantId}'. ");
 
-                foreach (var visibility in visibilities)
-                {
-                    if (entry.VisibilityId == visibility.Id && visibility.DisplayName.Contains("Public"))
-                    {
-                        AssertToGraphUriNode(graph, projectGraphName, cosc + "terms/project#visibility", cosc + $"terms/visibility#public");
-                        Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {cosc}terms/project#visibility {cosc}terms/visibility#public'. ");
-                        break;
-                    }
-                    else if (entry.VisibilityId == visibility.Id && visibility.DisplayName.Contains("Project Members"))
-                    {
-                        AssertToGraphUriNode(graph, projectGraphName, cosc + "terms/project#visibility", cosc + $"terms/visibility#projectMember");
-                        Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {cosc}terms/project#visibility {cosc}terms/visibility#projectMember'. ");
-                        break;
-                    }
-                }
+            if (entry.Visibility.DisplayName.Contains("Public"))
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.CoscineTermsProjectVisibility, RdfUris.CoscineTermsVisibilityPublic);
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.CoscineTermsProjectVisibility} {RdfUris.CoscineTermsVisibilityPublic}'. ");
+            }
+            else if (entry.Visibility.DisplayName.Contains("Project Members"))
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.CoscineTermsProjectVisibility, RdfUris.CoscineTermsVisibilityProjectMember);
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.CoscineTermsProjectVisibility} {RdfUris.CoscineTermsVisibilityProjectMember}'. ");
+            }
 
-                AssertToGraphLiteralNode(graph, projectGraphName, cosc + "terms/project#deleted", entry.Deleted.ToString().ToLower(), new Uri("http://www.w3.org/2001/XMLSchema#boolean"));
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {cosc}terms/project#deleted {entry.Deleted}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.CoscineTermsProjectDeleted, entry.Deleted.ToString().ToLower(), RdfUris.XsdBoolean);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.CoscineTermsProjectDeleted} {entry.Deleted}'. ");
 
-                AssertToGraphLiteralNode(graph, projectGraphName, cosc + "terms/project#slug", entry.Slug);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {cosc}terms/project#slug {entry.Slug}'. ");
+            AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.CoscineTermsProjectSlug, entry.Slug);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.CoscineTermsProjectSlug} {entry.Slug}'. ");
 
-                AssertToGraphUriNode(graph, projectGraphName, foaf + "homepage", projectHandleName);
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {foaf}homepage {projectHandleName}'. ");
+            AssertToGraphUriNode(graph, projectGraphName, RdfUris.FoafHomepage, projectHandleName);
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.FoafHomepage} {projectHandleName}'. ");
 
-                foreach (var projectRole in projectRoles.Where(p => p.ProjectId.Equals(entry.Id)))
-                {
-                    AssertToGraphUriNode(graph, projectGraphName, vcard + "hasMember", cosc + "users/" + projectRole.UserId);
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {vcard}hasMember {cosc}users/{projectRole.UserId}'. ");
-
-                    var blankNode = graph.CreateBlankNode();
+            foreach (var projectRole in entry.ProjectRoles)
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.VcardHasMember, UriHelper.TryCombineUri(RdfUris.CoscineUsers, projectRole.UserId));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.VcardHasMember} {UriHelper.TryCombineUri(RdfUris.CoscineUsers, projectRole.UserId)}'. ");
 
-                    AssertToGraphBlankAndUriNode(graph, blankNode, rdf + "type", org + "Membership");
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {rdf}type {org}Membership'. ");
+                var blankNode = graph.CreateBlankNode();
 
-                    AssertToGraphBlankAndUriNode(graph, blankNode, org + "organization", projectGraphName);
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {org}organization {projectGraphName}'. ");
+                AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.A, RdfUris.OrgMembershipClass);
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.A} {RdfUris.OrgMembershipClass}'. ");
 
-                    AssertToGraphBlankAndUriNode(graph, blankNode, org + "role", cosc + "roles/" + projectRole.RoleId);
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {org}role {cosc}roles/{projectRole.RoleId}'. ");
+                AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.OrgOrganization, projectGraphName);
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.OrgOrganization} {projectGraphName}'. ");
 
-                    AssertToGraphBlankAndUriNode(graph, blankNode, org + "member", cosc + "users/" + projectRole.UserId);
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {org}member {cosc}users/{projectRole.UserId}'. ");
-                }
+                AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.OrgRole, UriHelper.TryCombineUri(RdfUris.CoscineRoles, projectRole.RoleId));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.OrgRole} {UriHelper.TryCombineUri(RdfUris.CoscineRoles, projectRole.RoleId)}'. ");
 
-                foreach (var projectResource in projectResources.Where(p => p.ProjectId.Equals(entry.Id)))
-                {
-                    AssertToGraphUriNode(graph, projectGraphName, dcat + "catalog", $"{resourceUrlPrefix}/{projectResource.ResourceId}");
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcat}catalog {resourceUrlPrefix}/{projectResource.ResourceId}'. ");
-                }
+                AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.OrgMember, UriHelper.TryCombineUri(RdfUris.CoscineUsers, projectRole.UserId));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.OrgMember} {UriHelper.TryCombineUri(RdfUris.CoscineUsers, projectRole.UserId)}'. ");
+            }
 
-                foreach (var projectInstitute in projectInstitutes.Where(p => p.ProjectId.Equals(entry.Id)))
-                {
-                    AssertToGraphUriNode(graph, projectGraphName, org + "organization", projectInstitute.OrganizationUrl);
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {org}organization {projectInstitute.OrganizationUrl}'. ");
-                }
+            foreach (var projectResource in entry.ProjectResources)
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.DcatCatalog, UriHelper.TryCombineUri(RdfUris.CoscineResources, projectResource.ResourceId));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcatCatalog} {UriHelper.TryCombineUri(RdfUris.CoscineResources, projectResource.ResourceId)}'. ");
+            }
 
-                if (entry.Creator is not null)
-                {
-                    AssertToGraphUriNode(graph, projectGraphName, dcterms + "creator", cosc + $"users/{entry.Creator}");
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}creator {cosc}users/{entry.Creator}'. ");
-                }
+            foreach (var projectInstitute in entry.Organizations)
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.OrgOrganization, new Uri(projectInstitute.Uri));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.OrgOrganization} {projectInstitute.Uri}'. ");
+            }
 
+            if (entry.Creator is not null)
+            {
+                AssertToGraphUriNode(graph, projectGraphName, RdfUris.DcTermsCreator, UriHelper.TryCombineUri(RdfUris.CoscineUsers, entry.Creator.Id));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsCreator} {UriHelper.TryCombineUri(RdfUris.CoscineUsers, entry.Creator.Id)}'. ");
+            }
 
-                if (entry.DateCreated is not null && entry.DateCreated.HasValue)
-                {
-                    AssertToGraphLiteralNode(graph, projectGraphName, dcterms + "created", entry.DateCreated.Value.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {dcterms}created {entry.DateCreated}'. ");
-                }
 
-                graphs.Add(graph);
+            if (entry.CreationDate is not null && entry.CreationDate.HasValue)
+            {
+                AssertToGraphLiteralNode(graph, projectGraphName, RdfUris.DcTermsCreated, entry.CreationDate.Value.ToString(), RdfUris.XsdDateTime);
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{projectGraphName} {RdfUris.DcTermsCreated} {entry.CreationDate}'. ");
             }
-            return graphs;
+
+            graphs.Add(graph);
         }
+        return await Task.FromResult(graphs);
     }
 }
\ No newline at end of file
diff --git a/src/SQL2Linked/Implementations/ResourceStructuralData.cs b/src/SQL2Linked/Implementations/ResourceStructuralData.cs
index 53b8ab2..67eb96c 100644
--- a/src/SQL2Linked/Implementations/ResourceStructuralData.cs
+++ b/src/SQL2Linked/Implementations/ResourceStructuralData.cs
@@ -1,189 +1,162 @@
-using Coscine.Database.DataModel;
-using Coscine.Database.Models;
-using Coscine.Database.Util;
+using Coscine.ApiClient;
+using Coscine.ApiClient.Core.Model;
+using Newtonsoft.Json;
+using SQL2Linked.Utils;
 using VDS.RDF;
-using VDS.RDF.Query;
 
-namespace SQL2Linked.Implementations
+namespace SQL2Linked.Implementations;
+
+/// <summary>
+/// Class responsible for converting resource data into linked data graphs.
+/// It retrieves resource information from the API and then transforms this data into a series of RDF graphs,
+/// making use of predefined URIs and RDF constructs.
+/// </summary>
+public class ResourceStructuralData : StructuralData<ResourceAdminDto>
 {
-    public class ResourceStructuralData : StructuralData<Resource, ResourceModel>
+    /// <summary>
+    /// Asynchronously retrieves all resource data, including deleted resources.
+    /// </summary>
+    /// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a collection of <see cref="ResourceAdminDto"/>.</returns>
+    /// <remarks>This override allows for the inclusion of deleted resources.</remarks>
+    public override async Task<IEnumerable<ResourceAdminDto>> GetAll()
     {
-        public readonly Uri org = new("http://www.w3.org/ns/org#");
-        public readonly Uri dcat = new("http://www.w3.org/ns/dcat#");
-        public readonly Uri dcterms = new("http://purl.org/dc/terms/");
-        public readonly Uri acl = new("http://www.w3.org/ns/auth/acl#");
-        public readonly Uri foaf = new("http://xmlns.com/foaf/0.1/");
-        public readonly Uri pim = new("http://www.w3.org/ns/pim/space#");
-        public readonly Uri rdf = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
-        public readonly Uri cosc = new("https://purl.org/coscine/");
-        private VisibilityModel VisibilityModel = new VisibilityModel();
-        private ProjectResourceModel ProjectResourceModel = new ProjectResourceModel();
-        private LicenseModel LicenseModel = new LicenseModel();
-
-        private readonly Dictionary<string, string> _targetClassMap = new Dictionary<string, string>();
-
-        // Override to also receive deleted resources
-        public override IEnumerable<Resource> GetAll()
-        {
-            return DatabaseConnection.ConnectToDatabase((db) =>
-            {
-                return
-                    (from tableEntry in Model.GetITableFromDatabase(db)
-                     select tableEntry).ToList();
-            });
-        }
+        return await RequestUtil.WrapPagedRequest<ResourceAdminDtoPagedResponse, ResourceAdminDto>(
+            (currentPage) => _adminApi.GetAllResourcesAsync(includeDeleted: true, pageNumber: currentPage, pageSize: 250)
+        );
+    }
 
-        public override IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<Resource> entries)
-        {
-            IEnumerable<Visibility> visibilities = VisibilityModel.GetAll();
-            IEnumerable<ProjectResource> projectResources = ProjectResourceModel.GetAll();
-            IEnumerable<License> licenses = LicenseModel.GetAll();
+    /// <summary>
+    /// Converts a collection of resource data entries into a set of RDF graphs.
+    /// Each resource is transformed into a graph, with RDF triples representing various properties of the resource.
+    /// </summary>
+    /// <param name="entries">A collection of <see cref="ResourceAdminDto"/> instances representing resource data.</param>
+    /// <returns>A collection of <see cref="IGraph"/> instances, each representing an RDF graph of a resource.</returns>
+    public override async Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<ResourceAdminDto> entries)
+    {
+        var graphs = new List<IGraph>();
+        var coscineHandlePrefix = UriHelper.TryCombineUri(RdfUris.HandlePrefix, _pidConfiguration.Prefix)
+            ?? throw new Exception("Could not combine handle prefix with PID prefix");
 
-            var graphs = new List<IGraph>();
-            var resourceUrlHandlePrefix = "https://hdl.handle.net/" + Prefix;
-            var projectUrlPrefix = "https://purl.org/coscine/projects";
-            var resourceUrlPrefix = "https://purl.org/coscine/resources";
+        foreach (var entry in entries)
+        {
+            var resourceGraphName = UriHelper.TryCombineUri(RdfUris.CoscineResources, entry.Id)
+                ?? throw new Exception("Could not combine resources prefix with resource ID");
+            var resourceHandleName = UriHelper.TryCombineUri(coscineHandlePrefix, entry.Id);
 
-            foreach (var entry in entries)
+            var graph = new Graph
             {
-                var resourceGraphName = $"{resourceUrlPrefix}/{entry.Id}";
-                var resourceHandleName = $"{resourceUrlHandlePrefix}/{entry.Id}";
+                BaseUri = resourceGraphName
+            };
 
-                var graph = new Graph();
-                graph.BaseUri = new Uri(resourceGraphName);
+            AssertToGraphUriNode(graph, resourceGraphName, RdfUris.A, RdfUris.DcatCatalogClass);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.A} {RdfUris.DcatCatalogClass}'. ");
 
-                AssertToGraphUriNode(graph, resourceGraphName, rdf + "type", dcat + "Catalog");
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {rdf}type {dcat}Catalog'. ");
+            AssertToGraphUriNode(graph, resourceGraphName, RdfUris.A, RdfUris.PimStorageClass);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.A} {RdfUris.PimStorageClass}'. ");
 
-                AssertToGraphUriNode(graph, resourceGraphName, rdf + "type", pim + "Storage");
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {rdf}type {pim}Storage'. ");
+            AssertToGraphUriNode(graph, resourceGraphName, RdfUris.DcatService, UriHelper.TryCombineUri(RdfUris.CoscineResourceTypes, entry.Type.Id));
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcatService} {UriHelper.TryCombineUri(RdfUris.CoscineResourceTypes, entry.Type.Id)}'. ");
 
-                AssertToGraphUriNode(graph, resourceGraphName, dcat + "service", cosc + $"resourcetypes/{entry.TypeId}");
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcat}service {cosc}resourcetypes/{entry.TypeId}'. ");
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsTitle, entry.Name);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsTitle} {entry.Name}'. ");
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "title", entry.ResourceName);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}title {entry.ResourceName}'. ");
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsAlternative, entry.DisplayName);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsAlternative} {entry.DisplayName}'. ");
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "alternative", entry.DisplayName);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}alternative {entry.DisplayName}'. ");
-
-                foreach (var visibility in visibilities)
-                {
-                    if (entry.VisibilityId == visibility.Id && visibility.DisplayName.Contains("Public"))
-                    {
-                        AssertToGraphUriNode(graph, resourceGraphName, cosc + "terms/resource#visibility", cosc + $"terms/visibility#public");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {cosc}terms/resource#visibility {cosc}terms/visibility#public'. ");
-                        break;
-                    }
-                    else if (entry.VisibilityId == visibility.Id && visibility.DisplayName.Contains("Project Members"))
-                    {
-                        AssertToGraphUriNode(graph, resourceGraphName, cosc + "terms/resource#visibility", cosc + $"terms/visibility#projectMember");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {cosc}terms/resource#visibility {cosc}terms/visibility#projectMember'. ");
-                        break;
-                    }
-                }
+            if (entry.Visibility.DisplayName.Contains("Public"))
+            {
+                AssertToGraphUriNode(graph, resourceGraphName, RdfUris.CoscineTermsResourceVisibility, RdfUris.CoscineTermsVisibilityPublic);
+                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.CoscineTermsResourceVisibility} {RdfUris.CoscineTermsVisibilityPublic}'. ");
+            }
+            else if (entry.Visibility.DisplayName.Contains("Project Members"))
+            {
+                AssertToGraphUriNode(graph, resourceGraphName, RdfUris.CoscineTermsResourceVisibility, RdfUris.CoscineTermsVisibilityProjectMember);
+                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.CoscineTermsResourceVisibility} {RdfUris.CoscineTermsVisibilityProjectMember}'. ");
+            }
 
-                foreach (var license in licenses)
-                {
-                    if (entry.LicenseId == license.Id)
-                    {
-                        AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "license", license.DisplayName);
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}license {license.DisplayName}'. ");
-                        break;
-                    }
-                }
+            if (entry.License is not null)
+            {
+                AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsLicense, entry.License.DisplayName);
+                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsLicense} {entry.License.DisplayName}'. ");
+            }
 
-                if (!string.IsNullOrWhiteSpace(entry.Keywords))
+            if (entry.Keywords.Count > 0)
+            {
+                foreach (var keyword in entry.Keywords)
                 {
-                    var listKeywords = entry.Keywords.Split(';').ToList();
-                    foreach (var keyword in listKeywords)
-                    {
-                        AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "subject", keyword);
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}subject {keyword}'. ");
-                    }
+                    AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsSubject, keyword);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsSubject} {keyword}'. ");
                 }
+            }
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "rights", entry.UsageRights);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}rights {entry.UsageRights}'. ");
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsRights, entry.UsageRights);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsRights} {entry.UsageRights}'. ");
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "description", entry.Description);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}description {entry.Description}'. ");
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsDescription, entry.Description);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsDescription} {entry.Description}'. ");
 
-                // Skipping broken resources
-                if (string.IsNullOrWhiteSpace(entry.ApplicationProfile))
-                {
-                    continue;
-                }
-
-                AssertToGraphUriNode(graph, resourceGraphName, dcterms + "conformsTo", entry.ApplicationProfile);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}conformsTo {entry.ApplicationProfile}'. ");
+            // Skipping broken resources
+            if (string.IsNullOrWhiteSpace(entry.ApplicationProfile.Uri))
+            {
+                continue;
+            }
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, cosc + "terms/resource#fixedValues", entry.FixedValues);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {cosc}terms/resource#fixedValues {entry.FixedValues}'. ");
+            AssertToGraphUriNode(graph, resourceGraphName, RdfUris.DcTermsConformsTo, new Uri(entry.ApplicationProfile.Uri));
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsConformsTo} {entry.ApplicationProfile}'. ");
 
-                if (entry.Creator is not null)
-                {
-                    AssertToGraphUriNode(graph, resourceGraphName, dcterms + "creator", cosc + $"users/{entry.Creator}");
-                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}creator {cosc}users/{entry.Creator}'. ");
-                }
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.CoscineTermsResourceFixedValues, JsonConvert.SerializeObject(entry.FixedValues));
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.CoscineTermsResourceFixedValues} {JsonConvert.SerializeObject(entry.FixedValues)}'. ");
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, cosc + "terms/resource#archived", entry.Archived.ToString().ToLower(), new Uri("http://www.w3.org/2001/XMLSchema#boolean"));
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {cosc}terms/resource#archived {entry.Archived}'. ");
+            if (entry.Creator is not null)
+            {
+                AssertToGraphUriNode(graph, resourceGraphName, RdfUris.DcTermsCreator, UriHelper.TryCombineUri(RdfUris.CoscineUsers, entry.Creator.Id));
+                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsCreator} {UriHelper.TryCombineUri(RdfUris.CoscineUsers, entry.Creator.Id)}'. ");
+            }
 
-                AssertToGraphUriNode(graph, resourceGraphName, foaf + "homepage", resourceHandleName);
-                Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {foaf}homepage {resourceGraphName}'. ");
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.CoscineTermsResourceArchived, entry.Archived.ToString().ToLower(), new Uri("http://www.w3.org/2001/XMLSchema#boolean"));
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.CoscineTermsResourceArchived} {entry.Archived}'. ");
 
-                AssertToGraphLiteralNode(graph, resourceGraphName, cosc + "terms/resource#deleted", entry.Deleted.ToString().ToLower(), new Uri("http://www.w3.org/2001/XMLSchema#boolean"));
-                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{resourceGraphName} {cosc}terms/resource#deleted {entry.Deleted}'. ");
+            AssertToGraphUriNode(graph, resourceGraphName, RdfUris.FoafHomepage, resourceHandleName);
+            Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.FoafHomepage} {resourceGraphName}'. ");
 
-                // Reinstate the catalog assignments
-                var cmdString = new SparqlParameterizedString
-                {
-                    CommandText = "SELECT DISTINCT ?o WHERE { <" + resourceGraphName + "> <http://www.w3.org/ns/dcat#catalog> ?o }"
-                };
-                var resultSet = WrapRequest(() => RdfStoreConnector.QueryEndpoint.QueryWithResultSet(cmdString.ToString()));
-                foreach (var result in resultSet)
-                {
-                    AssertToGraphUriNode(graph, resourceGraphName, dcat + "catalog", result[0].ToString());
-                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcat}catalog {result[0].ToString()}'. ");
-                }
+            AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.CoscineTermsResourceDeleted, entry.Deleted.ToString().ToLower(), new Uri("http://www.w3.org/2001/XMLSchema#boolean"));
+            Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.CoscineTermsResourceDeleted} {entry.Deleted}'. ");
 
-                foreach (var projectResource in projectResources)
+            foreach (var projectResource in entry.ProjectResources)
+            {
+                if (entry.Id == projectResource.ResourceId)
                 {
-                    if (entry.Id == projectResource.ResourceId)
-                    {
-                        var blankNode = graph.CreateBlankNode();
-
-                        AssertToGraphBlankAndUriNode(graph, blankNode, rdf + "type", acl + "Authorization");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {rdf}type {acl}Authorization'. ");
+                    var blankNode = graph.CreateBlankNode();
 
-                        AssertToGraphBlankAndUriNode(graph, blankNode, acl + "agentGroup", $"{projectUrlPrefix}/{projectResource.ProjectId}");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {acl}agentGroup {projectUrlPrefix}/{projectResource.ProjectId}'. ");
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.A, RdfUris.AclAuthorizationClass);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.A} {RdfUris.AclAuthorizationClass}'. ");
 
-                        AssertToGraphBlankAndUriNode(graph, blankNode, acl + "accessTo", resourceGraphName);
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {acl}accessTo {resourceGraphName}'. ");
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.AclAgentGroup, UriHelper.TryCombineUri(RdfUris.CoscineProjects, projectResource.ProjectId));
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.AclAgentGroup} {UriHelper.TryCombineUri(RdfUris.CoscineProjects, projectResource.ProjectId)}'. ");
 
-                        AssertToGraphBlankAndUriNode(graph, blankNode, acl + "default", resourceGraphName);
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {acl}default {resourceGraphName}'. ");
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.AclAccessTo, resourceGraphName);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.AclAccessTo} {resourceGraphName}'. ");
 
-                        AssertToGraphBlankAndUriNode(graph, blankNode, acl + "mode", acl + "Read");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {acl}accessTo {acl}Read'. ");
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.AclDefault, resourceGraphName);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.AclDefault} {resourceGraphName}'. ");
 
-                        AssertToGraphBlankAndUriNode(graph, blankNode, acl + "mode", acl + "Write");
-                        Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {acl}accessTo {acl}Write'. ");
-                    }
-                }
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.AclMode, RdfUris.AclReadClass);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.AclMode} {RdfUris.AclReadClass}'. ");
 
-                if (entry.DateCreated is not null && entry.DateCreated.HasValue)
-                {
-                    AssertToGraphLiteralNode(graph, resourceGraphName, dcterms + "created", entry.DateCreated.Value.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
-                    Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{resourceGraphName} {dcterms}created {entry.DateCreated}'. ");
+                    AssertToGraphBlankAndUriNode(graph, blankNode, RdfUris.AclMode, RdfUris.AclWriteClass);
+                    Console.WriteLine($"For resource '{entry.DisplayName}' will migrate triple '{blankNode} {RdfUris.AclMode} {RdfUris.AclWriteClass}'. ");
                 }
+            }
 
-                graphs.Add(graph);
+            if (entry.DateCreated is not null && entry.DateCreated.HasValue)
+            {
+                AssertToGraphLiteralNode(graph, resourceGraphName, RdfUris.DcTermsCreated, entry.DateCreated.Value.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#dateTime"));
+                Console.WriteLine($"For project '{entry.DisplayName}' will migrate triple '{resourceGraphName} {RdfUris.DcTermsCreated} {entry.DateCreated}'. ");
             }
 
-            return graphs;
+            graphs.Add(graph);
         }
+
+        return await Task.FromResult(graphs);
     }
 }
diff --git a/src/SQL2Linked/Implementations/ResourceTypeStructuralData.cs b/src/SQL2Linked/Implementations/ResourceTypeStructuralData.cs
index d2536f6..db049ae 100644
--- a/src/SQL2Linked/Implementations/ResourceTypeStructuralData.cs
+++ b/src/SQL2Linked/Implementations/ResourceTypeStructuralData.cs
@@ -1,57 +1,97 @@
-using Coscine.Database.DataModel;
-using Coscine.Database.Models;
+using Coscine.ApiClient.Core.Api;
+using Coscine.ApiClient.Core.Model;
+using SQL2Linked.Utils;
 using VDS.RDF;
+using VDS.RDF.Parsing;
 
-namespace SQL2Linked.Implementations
+namespace SQL2Linked.Implementations;
+
+/// <summary>
+/// Class responsible for converting resource type data into linked data graphs.
+/// It retrieves resource type information from the API and then transforms this data into a series of RDF graphs,
+/// making use of predefined URIs and RDF constructs.
+/// </summary>
+public class ResourceTypeStructuralData : StructuralData<ResourceTypeInformationDto>
 {
-    public class ResourceTypeStructuralData : StructuralData<ResourceType, ResourceTypeModel>
+    /// <summary>
+    /// Asynchronously retrieves all resource type data.
+    /// </summary>
+    /// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a collection of <see cref="ResourceTypeInformationDto"/>.</returns>
+    public override async Task<IEnumerable<ResourceTypeInformationDto>> GetAll()
+    {
+        var resourceTypeApi = new ResourceTypeApi(_apiConfiguration);
+        var resourceTypeInformationsResponse = await resourceTypeApi.GetAllResourceTypesInformationAsync();
+        return resourceTypeInformationsResponse.Data;
+    }
+
+    /// <summary>
+    /// Converts a collection of resource type data entries into a set of RDF graphs.
+    /// Each resource type is transformed into a graph, with RDF triples representing various properties of the resource type.
+    /// </summary>
+    /// <param name="entries">A collection of <see cref="ResourceTypeInformationDto"/> instances representing resource type data.</param>
+    /// <returns>A collection of <see cref="IGraph"/> instances, each representing an RDF graph of a resource type.</returns>
+    public override async Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<ResourceTypeInformationDto> entries)
     {
-        public readonly string ResourceTypeUrlPrefix = "https://purl.org/coscine/resourcetypes";
-        public readonly Uri rdf = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
-        public readonly Uri dcat = new("http://www.w3.org/ns/dcat#");
-        public readonly Uri dcterms = new("http://purl.org/dc/terms/");
-        public override IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<ResourceType> entries)
+        var graphs = new List<IGraph>();
+
+        foreach (var entry in entries)
         {
+            var resourceTypeGraphName = UriHelper.TryCombineUri(RdfUris.CoscineResourceTypes, entry.Id)
+                ?? throw new Exception("Could not combine resource types prefix with resource type ID");
+            var response = _adminApi.GetMetadataGraph(resourceTypeGraphName.AbsoluteUri, RdfFormat.TextTurtle);
+
+            var graph = new Graph()
+            {
+                BaseUri = resourceTypeGraphName
+            };
+
+            graph.LoadFromString(response.Data.Content, new TurtleParser());
 
-            var graphs = new List<IGraph>();
-
-            foreach (var entry in entries)
-            {
-                var resourceTypeGraphName = $"{ResourceTypeUrlPrefix}/{entry.Id}";
-                var graph = RdfStoreConnector.GetGraph(resourceTypeGraphName);
-
-                // check if a triple with a dcat:DataService already exists in the resourcetype graph
-                var getTriplesDcatDataService = graph.GetTriplesWithObject(new Uri(dcat + "DataService"));
-
-                if (!getTriplesDcatDataService.Any())
-                {
-                    AssertToGraphUriNode(graph, resourceTypeGraphName, rdf + "type", dcat + "DataService");
-                    Console.WriteLine($"For resource type '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {rdf}type {dcat}DataService'. ");
-                }
-                else
-                {
-                    Console.WriteLine($"For resource type '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {rdf}type {dcat}DataService'. ");
-                }
-
-                // check if a triple with dcterms:title '{entry.DisplayName}' already exists in the role graph
-                var getTriplesDctermsTitle = graph.GetTriplesWithPredicate(new Uri(dcterms + "title"));
-
-                if (!getTriplesDctermsTitle.Any())
-                {
-                    AssertToGraphLiteralNode(graph, resourceTypeGraphName, dcterms + "title", entry.DisplayName);
-                    Console.WriteLine($"For resource type '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {dcterms}title {entry.DisplayName}'. ");
-                }
-                else
-                {
-                    Console.WriteLine($"For resource type '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {dcterms}title {entry.DisplayName}'. ");
-                }
-                if (!getTriplesDcatDataService.Any() || !getTriplesDctermsTitle.Any())
-                {
-                    graphs.Add(graph);
-                }
+            // check if a triple with a dcat:DataService already exists in the resourcetype graph
+            var getTriplesDcatDataService = graph.GetTriplesWithObject(RdfUris.DcatDataServiceClass);
+
+            if (!getTriplesDcatDataService.Any())
+            {
+                AssertToGraphUriNode(graph, resourceTypeGraphName, RdfUris.A, RdfUris.DcatDataServiceClass);
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will migrate triple '{graph.BaseUri} {RdfUris.A} {RdfUris.DcatDataServiceClass}'. ");
+            }
+            else
+            {
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will NOT migrate triple '{graph.BaseUri} {RdfUris.A} {RdfUris.DcatDataServiceClass}'. ");
+            }
+
+            // check if a triple with dcterms:title '{entry.DisplayName}' already exists in the role graph
+            var getTriplesDctermsTitle = graph.GetTriplesWithPredicate(RdfUris.DcTermsTitle);
+
+            if (!getTriplesDctermsTitle.Any())
+            {
+                AssertToGraphLiteralNode(graph, resourceTypeGraphName, RdfUris.DcTermsTitle, entry.SpecificType);
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will migrate triple '{graph.BaseUri} {RdfUris.DcTermsTitle} {entry.SpecificType}'. ");
+            }
+            else
+            {
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will NOT migrate triple '{graph.BaseUri} {RdfUris.DcTermsTitle} {entry.SpecificType}'. ");
+            }
+
+
+            // check if a triple with dcterms:title '{entry.DisplayName}' already exists in the role graph
+            var getTriplesDctermsAlternative = graph.GetTriplesWithPredicate(RdfUris.DcTermsAlternative);
+
+            if (!getTriplesDctermsAlternative.Any())
+            {
+                AssertToGraphLiteralNode(graph, resourceTypeGraphName, RdfUris.DcTermsAlternative, entry.GeneralType);
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will migrate triple '{graph.BaseUri} {RdfUris.DcTermsAlternative} {entry.GeneralType}'. ");
+            }
+            else
+            {
+                Console.WriteLine($"For resource type '{entry.SpecificType}' will NOT migrate triple '{graph.BaseUri} {RdfUris.DcTermsAlternative} {entry.GeneralType}'. ");
+            }
+
+            if (!getTriplesDcatDataService.Any() || !getTriplesDctermsTitle.Any())
+            {
+                graphs.Add(graph);
             }
-            return graphs;
         }
+        return await Task.FromResult(graphs);
     }
-
 }
\ No newline at end of file
diff --git a/src/SQL2Linked/Implementations/RoleStructuralData.cs b/src/SQL2Linked/Implementations/RoleStructuralData.cs
index 04b3176..dcd81ce 100644
--- a/src/SQL2Linked/Implementations/RoleStructuralData.cs
+++ b/src/SQL2Linked/Implementations/RoleStructuralData.cs
@@ -1,57 +1,84 @@
-using Coscine.Database.DataModel;
-using Coscine.Database.Models;
+using Coscine.ApiClient;
+using Coscine.ApiClient.Core.Api;
+using Coscine.ApiClient.Core.Model;
+using SQL2Linked.Utils;
 using VDS.RDF;
+using VDS.RDF.Parsing;
 
-namespace SQL2Linked.Implementations
+namespace SQL2Linked.Implementations;
+
+/// <summary>
+/// Class responsible for converting role data into linked data graphs.
+/// It retrieves role information from the API and then transforms this data into a series of RDF graphs,
+/// making use of predefined URIs and RDF constructs.
+/// </summary>
+public class RoleStructuralData : StructuralData<RoleDto>
 {
-    public class RoleStructuralData : StructuralData<Role, RoleModel>
+    /// <summary>
+    /// Asynchronously retrieves all role data.
+    /// </summary>
+    /// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a collection of <see cref="RoleDto"/>.</returns>
+    public override async Task<IEnumerable<RoleDto>> GetAll()
     {
-        public readonly string RoleUrlPrefix = "https://purl.org/coscine/roles";
-        public readonly Uri cosc = new("https://purl.org/coscine/");
-        public readonly Uri rdf = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
-        public readonly Uri org = new("http://www.w3.org/ns/org#");
-        public readonly Uri dcterms = new("http://purl.org/dc/terms/");
+        var roleApi = new RoleApi(_apiConfiguration);
+        return await RequestUtil.WrapPagedRequest<RoleDtoPagedResponse, RoleDto>(
+            (currentPage) => roleApi.GetRolesAsync(pageNumber: currentPage)
+        );
+    }
 
-        public override IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<Role> entries)
+    /// <summary>
+    /// Converts a collection of role data entries into a set of RDF graphs.
+    /// Each role is transformed into a graph, with RDF triples representing various properties of the role.
+    /// </summary>
+    /// <param name="entries">A collection of <see cref="RoleDto"/> instances representing role data.</param>
+    /// <returns>A collection of <see cref="IGraph"/> instances, each representing an RDF graph of a role.</returns>
+    public override async Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<RoleDto> entries)
+    {
+        var graphs = new List<IGraph>();
+
+        foreach (var entry in entries)
         {
-            var graphs = new List<IGraph>();
+            var roleGraphName = UriHelper.TryCombineUri(RdfUris.CoscineRoles, entry.Id)
+                ?? throw new Exception("Could not combine role prefix with role ID");
+            var response = await _adminApi.GetMetadataGraphAsync(roleGraphName.AbsoluteUri, RdfFormat.TextTurtle);
+
+            var graph = new Graph()
+            {
+                BaseUri = roleGraphName
+            };
+
+            graph.LoadFromString(response.Data.Content, new TurtleParser());
+
+            // check if a triple with a org:role already exists in the role graph
+            var getTriplesOrgRole = graph.GetTriplesWithObject(RdfUris.OrgRoleClass);
+
+            if (!getTriplesOrgRole.Any())
+            {
+                AssertToGraphUriNode(graph, roleGraphName, RdfUris.A, RdfUris.OrgRoleClass);
+                Console.WriteLine($"For role '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {RdfUris.A} {RdfUris.OrgRoleClass}'. ");
+            }
+            else
+            {
+                Console.WriteLine($"For role '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {RdfUris.A} {RdfUris.OrgRoleClass}'. ");
+            }
+
+            // check if a triple with dcterms:title '{entry.DisplayName}' already exists in the role graph
+            var getTriplesDctermsTitle = graph.GetTriplesWithPredicate(RdfUris.DcTermsTitle);
 
-            foreach (var entry in entries)
+            if (!getTriplesDctermsTitle.Any())
+            {
+                AssertToGraphLiteralNode(graph, roleGraphName, RdfUris.DcTermsTitle, entry.DisplayName);
+                Console.WriteLine($"For role '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {RdfUris.DcTermsTitle} {entry.DisplayName}'. ");
+            }
+            else
+            {
+                Console.WriteLine($"For role '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {RdfUris.DcTermsTitle} {entry.DisplayName}'. ");
+            }
+            if (!getTriplesOrgRole.Any() || !getTriplesDctermsTitle.Any())
             {
-                var roleGraphName = $"{RoleUrlPrefix}/{entry.Id}";
-                var graph = RdfStoreConnector.GetGraph(roleGraphName);
-
-                // check if a triple with a org:role already exists in the role graph
-                var getTriplesOrgRole = graph.GetTriplesWithObject(new Uri(org + "Role"));
-
-                if (!getTriplesOrgRole.Any())
-                {
-                    AssertToGraphUriNode(graph, roleGraphName, rdf + "type", org + "Role");
-                    Console.WriteLine($"For role '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {rdf}type {org}Role'. ");
-                }
-                else
-                {
-                    Console.WriteLine($"For role '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {rdf}type {org}Role'. ");
-                }
-
-                // check if a triple with dcterms:title '{entry.DisplayName}' already exists in the role graph
-                var getTriplesDctermsTitle = graph.GetTriplesWithPredicate(new Uri(dcterms + "title"));
-
-                if (!getTriplesDctermsTitle.Any())
-                {
-                    AssertToGraphLiteralNode(graph, roleGraphName, dcterms + "title", entry.DisplayName);
-                    Console.WriteLine($"For role '{entry.DisplayName}' will migrate triple '{graph.BaseUri} {dcterms}title {entry.DisplayName}'. ");
-                }
-                else
-                {
-                    Console.WriteLine($"For role '{entry.DisplayName}' will NOT migrate triple '{graph.BaseUri} {dcterms}title {entry.DisplayName}'. ");
-                }
-                if (!getTriplesOrgRole.Any() || !getTriplesDctermsTitle.Any())
-                {
-                    graphs.Add(graph);
-                }
+                graphs.Add(graph);
             }
-            return graphs;
         }
+        return graphs;
     }
 }
\ No newline at end of file
diff --git a/src/SQL2Linked/Implementations/UserStructuralData.cs b/src/SQL2Linked/Implementations/UserStructuralData.cs
index 59a6999..374205c 100644
--- a/src/SQL2Linked/Implementations/UserStructuralData.cs
+++ b/src/SQL2Linked/Implementations/UserStructuralData.cs
@@ -1,53 +1,75 @@
-using Coscine.Database.DataModel;
-using Coscine.Database.Models;
-using Coscine.Metadata;
+using Coscine.ApiClient;
+using Coscine.ApiClient.Core.Model;
+using SQL2Linked.Utils;
 using VDS.RDF;
+using VDS.RDF.Parsing;
 
-namespace SQL2Linked.Implementations
+namespace SQL2Linked.Implementations;
+
+/// <summary>
+/// Class responsible for converting user data into linked data graphs.
+/// It retrieves user information from the API and then transforms this data into a series of RDF graphs,
+/// making use of predefined URIs and RDF constructs.
+/// </summary>
+public class UserStructuralData : StructuralData<UserDto>
 {
-    public class UserStructuralData : StructuralData<User, UserModel>
+    /// <summary>
+    /// Asynchronously retrieves all user data only for users who have accepted the ToS.
+    /// </summary>
+    /// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a collection of <see cref="UserDto"/>.</returns>
+    /// <remarks>This override allows for the retrieval of users who have accepted the ToS.</remarks>
+    public override async Task<IEnumerable<UserDto>> GetAll()
     {
-        public readonly string UserUrlPrefix = "https://purl.org/coscine/users";
-        public readonly Uri rdf = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
-        public readonly Uri foaf = new("http://xmlns.com/foaf/0.1/");
+        return await RequestUtil.WrapPagedRequest<UserDtoPagedResponse, UserDto>(
+            (currentPage) => _adminApi.GetAllUsersAsync(tosAccepted: true, pageNumber: currentPage, pageSize: 250)
+        );
+    }
 
-        // Override to only transform users which have accepted the TOS
-        public override IEnumerable<User> GetAll()
-        {
-            return Model.GetAllWhere((user) => user.Tosaccepteds.Any());
-        }
+    /// <summary>
+    /// Converts a collection of user data entries into a set of RDF graphs.
+    /// Each user is transformed into a graph, with RDF triples representing various properties of the user.
+    /// </summary>
+    /// <param name="entries">A collection of <see cref="UserDto"/> instances representing user data.</param>
+    /// <returns>A collection of <see cref="IGraph"/> instances, each representing an RDF graph of a user.</returns>
+    public override async Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<UserDto> entries)
+    {
+        var graphs = new List<IGraph>();
 
-        public override IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<User> entries)
+        foreach (var entry in entries)
         {
-            var graphs = new List<IGraph>();
+            var userGraphName = UriHelper.TryCombineUri(RdfUris.CoscineUsers, entry.Id)
+                ?? throw new Exception("Could not combine users prefix with user ID");
+            var response = _adminApi.GetMetadataGraph(userGraphName.AbsoluteUri, RdfFormat.TextTurtle);
 
-            foreach (var entry in entries)
+            var graph = new Graph()
             {
-                var userGraphName = $"{UserUrlPrefix}/{entry.Id}";
-                var graph = RdfStoreConnector.GetGraph(userGraphName);
+                BaseUri = userGraphName
+            };
 
-                // check if a triple with a foaf:Person already exists in the user graph
-                var getTriples = graph.GetTriplesWithObject(new Uri(foaf + "Person"));
-                // check if the current display name is already applied in the user graph
-                var getTriplesName = graph.GetTriplesWithPredicate(new Uri(foaf + "name"));
+            graph.LoadFromString(response.Data.Content, new TurtleParser());
 
-                if (!getTriples.Any() || !getTriplesName.Any((triple) => triple.Object.ToString() == entry.DisplayName))
-                {
-                    AssertToGraphUriNode(graph, userGraphName, rdf + "type", foaf + "Person");
+            // check if a triple with a foaf:Person already exists in the user graph
+            var getTriples = graph.GetTriplesWithObject(RdfUris.FoafPersonClass);
+            // check if the current display name is already applied in the user graph
+            var getTriplesName = graph.GetTriplesWithPredicate(RdfUris.FoafName);
 
-                    graph.Retract(getTriplesName);
-                    AssertToGraphLiteralNode(graph, userGraphName, foaf + "name", entry.DisplayName);
+            if (!getTriples.Any() || !getTriplesName.Any((triple) => (triple.Object as ILiteralNode)?.Value == entry.DisplayName))
+            {
+                AssertToGraphUriNode(graph, userGraphName, RdfUris.A, RdfUris.FoafPersonClass);
+                Console.WriteLine($"For user '{entry.DisplayName}' will migrate triple '{userGraphName} {RdfUris.A} {RdfUris.FoafPersonClass}'. ");
+
+                graph.Retract(getTriplesName);
+                AssertToGraphLiteralNode(graph, userGraphName, RdfUris.FoafName, entry.DisplayName);
 
-                    graphs.Add(graph);
+                graphs.Add(graph);
 
-                    Console.WriteLine($"Will migrate user '{entry.DisplayName}' with id '{entry.Id}'.");
-                }
-                else
-                {
-                    Console.WriteLine($"Will NOT migrate user '{entry.DisplayName}' with id '{entry.Id}'.");
-                }
+                Console.WriteLine($"Will migrate user '{entry.DisplayName}' with id '{entry.Id}'.");
+            }
+            else
+            {
+                Console.WriteLine($"Will NOT migrate user '{entry.DisplayName}' with id '{entry.Id}'.");
             }
-            return graphs;
         }
+        return await Task.FromResult(graphs);
     }
 }
diff --git a/src/SQL2Linked/Models/ConfigurationModels/PidConfiguration.cs b/src/SQL2Linked/Models/ConfigurationModels/PidConfiguration.cs
new file mode 100644
index 0000000..ebdea92
--- /dev/null
+++ b/src/SQL2Linked/Models/ConfigurationModels/PidConfiguration.cs
@@ -0,0 +1,17 @@
+namespace SQL2Linked.Models.ConfigurationModels;
+
+/// <summary>
+/// Represents the configuration settings for the PID ePIC API used in the application.
+/// </summary>
+public class PidConfiguration
+{
+    /// <summary>
+    /// The section name in the configuration file.
+    /// </summary>
+    public static readonly string Section = "PidConfiguration";
+
+    /// <summary>
+    /// Prefix for the PID ePIC API.
+    /// </summary>
+    public string Prefix { get; init; } = null!;
+}
diff --git a/src/SQL2Linked/Models/ConfigurationModels/SQL2LinkedConfiguration.cs b/src/SQL2Linked/Models/ConfigurationModels/SQL2LinkedConfiguration.cs
new file mode 100644
index 0000000..178a2b4
--- /dev/null
+++ b/src/SQL2Linked/Models/ConfigurationModels/SQL2LinkedConfiguration.cs
@@ -0,0 +1,17 @@
+namespace SQL2Linked.Models.ConfigurationModels;
+
+/// <summary>
+/// Represents the configuration settings used in the application.
+/// </summary>
+public class SQL2LinkedConfiguration
+{
+    /// <summary>
+    /// The section name in the configuration file.
+    /// </summary>
+    public static readonly string Section = "SQL2LinkedConfiguration";
+
+    /// <summary>
+    /// Value indicating whether SQL2Linked is enabled.
+    /// </summary>
+    public bool IsEnabled { get; init; }
+}
\ No newline at end of file
diff --git a/src/SQL2Linked/Program.cs b/src/SQL2Linked/Program.cs
index b9d0aa6..bd2579c 100644
--- a/src/SQL2Linked/Program.cs
+++ b/src/SQL2Linked/Program.cs
@@ -1,27 +1,98 @@
-using SQL2Linked.Implementations;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using SQL2Linked.Implementations;
+using SQL2Linked.Models.ConfigurationModels;
+using Winton.Extensions.Configuration.Consul;
 
-var dummyMode = !(args.Length > 0 && args[0] == "--noDryRun");
-if (dummyMode)
+namespace SQL2Linked;
+
+public class Program
 {
-    Console.WriteLine("\n DUMMY MODE \n");
-    Console.WriteLine(" To exit dummy mode, execute with the \"--noDryRun\" argument");
-}
+    private static IServiceProvider _serviceProvider = null!;
+
+    private static async Task Main(string[] args)
+    {
+        InitializeServices();
+
+        var sql2LinkedConfiguration = _serviceProvider.GetRequiredService<IOptionsMonitor<SQL2LinkedConfiguration>>().CurrentValue;
+        if (!sql2LinkedConfiguration.IsEnabled)
+        {
+            Console.WriteLine("SQL 2 Linked Data migration is disabled. To enable it, set the \"IsEnabled\" property to \"true\" in the configuration.");
+            return;
+        }
+
+        var dummyMode = !(args.Length > 0 && args[0] == "--noDryRun");
+        if (dummyMode)
+        {
+            Console.WriteLine("\n DUMMY MODE \n");
+            Console.WriteLine(" To exit dummy mode, execute with the \"--noDryRun\" argument");
+        }
+
+        Console.WriteLine("\nBegin SQL 2 Linked Data migration");
+
+        var roleStructuralData = _serviceProvider.GetRequiredService<RoleStructuralData>();
+        await roleStructuralData.Migrate(dummyMode);
+
+        var userStructuralData = _serviceProvider.GetRequiredService<UserStructuralData>();
+        await userStructuralData.Migrate(dummyMode);
+
+        var resourceTypeStructuralData = _serviceProvider.GetRequiredService<ResourceTypeStructuralData>();
+        await resourceTypeStructuralData.Migrate(dummyMode);
+
+        var projectStructuralData = _serviceProvider.GetRequiredService<ProjectStructuralData>();
+        await projectStructuralData.Migrate(dummyMode);
+
+        var resourceStructuralData = _serviceProvider.GetRequiredService<ResourceStructuralData>();
+        await resourceStructuralData.Migrate(dummyMode);
+
+        Console.WriteLine("\n Finished.");
+    }
+
+    private static void InitializeServices()
+    {
+        // Create a new instance of ConfigurationBuilder
+        var configBuilder = new ConfigurationBuilder();
 
-Console.WriteLine("\nBegin SQL 2 Linked Data migration");
+        // Define the Consul URL
+        var consulUrl = Environment.GetEnvironmentVariable("CONSUL_URL") ?? "http://localhost:8500";
 
-var roleStructuralData = new RoleStructuralData();
-roleStructuralData.Migrate(dummyMode);
+        // Remove the default sources
+        configBuilder.Sources.Clear();
 
-var userStructuralData = new UserStructuralData();
-userStructuralData.Migrate(dummyMode);
+        // Add Consul as a configuration source
+        var configuration = configBuilder
+            .AddConsul(
+                "coscine/Coscine.Infrastructure/SQL2Linked/appsettings",
+                options =>
+                {
+                    options.ConsulConfigurationOptions =
+                        cco => cco.Address = new Uri(consulUrl);
+                    options.Optional = true;
+                    options.ReloadOnChange = true;
+                    options.PollWaitTime = TimeSpan.FromSeconds(5);
+                    options.OnLoadException = exceptionContext => exceptionContext.Ignore = true;
+                }
+            )
+            .AddEnvironmentVariables()
+            .Build();
 
-var resourceTypeStructuralData = new ResourceTypeStructuralData();
-resourceTypeStructuralData.Migrate(dummyMode);
+        var services = new ServiceCollection()
+            .AddSingleton<IConfiguration>(configuration);
 
-var projectStructuralData = new ProjectStructuralData();
-projectStructuralData.Migrate(dummyMode);
+        // Add the configuration to the service collection
+        services.Configure<SQL2LinkedConfiguration>(settings =>
+        {
+            configuration.GetSection(SQL2LinkedConfiguration.Section).Bind(settings);
+        });
 
-var resourceStructuralData = new ResourceStructuralData();
-resourceStructuralData.Migrate(dummyMode);
+        // Add the services to the service collection
+        services.AddTransient<ProjectStructuralData>();
+        services.AddTransient<ResourceStructuralData>();
+        services.AddTransient<ResourceTypeStructuralData>();
+        services.AddTransient<RoleStructuralData>();
+        services.AddTransient<UserStructuralData>();
 
-Console.WriteLine("\n Finished.");
+        _serviceProvider = services.BuildServiceProvider();
+    }
+}
\ No newline at end of file
diff --git a/src/SQL2Linked/SQL2Linked.csproj b/src/SQL2Linked/SQL2Linked.csproj
index 9c2df07..7d22d4c 100644
--- a/src/SQL2Linked/SQL2Linked.csproj
+++ b/src/SQL2Linked/SQL2Linked.csproj
@@ -1,16 +1,25 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
-  <PropertyGroup>
-    <OutputType>Exe</OutputType>
-    <TargetFramework>net6.0</TargetFramework>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
-  <Version>0.1.19</Version></PropertyGroup>
+	<PropertyGroup>
+		<OutputType>Exe</OutputType>
+		<TargetFramework>net8.0</TargetFramework>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<Nullable>enable</Nullable>
+		<Version>0.1.19</Version>
+	</PropertyGroup>
 
-  <ItemGroup>
-    <PackageReference Include="Coscine.Database" Version="2.*-*" />
-    <PackageReference Include="Coscine.Metadata" Version="2.*-*" />
-    <PackageReference Include="Polly" Version="7.2.3" />
-  </ItemGroup>
+	<PropertyGroup>
+		<Authors>RWTH Aachen University</Authors>
+		<Company>IT Center, RWTH Aachen University</Company>
+		<Copyright>©2024 IT Center, RWTH Aachen University</Copyright>
+		<Description>SQL2Linked is a part of the Coscine group.</Description>
+	</PropertyGroup>
+
+	<ItemGroup>
+		<PackageReference Include="Coscine.ApiClient" Version="1.3.0-issue-2666-admin0011" />
+		<PackageReference Include="dotNetRdf" Version="3.1.1" />
+		<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
+		<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
+	</ItemGroup>
 
 </Project>
diff --git a/src/SQL2Linked/StructuralData.cs b/src/SQL2Linked/StructuralData.cs
index ea4d2d8..70dc878 100644
--- a/src/SQL2Linked/StructuralData.cs
+++ b/src/SQL2Linked/StructuralData.cs
@@ -1,172 +1,178 @@
-using Coscine.Configuration;
-using Coscine.Database.Models;
-using Coscine.Metadata;
-using Polly;
+using Coscine.ApiClient;
+using Coscine.ApiClient.Core.Api;
+using Coscine.ApiClient.Core.Client;
+using Coscine.ApiClient.Core.Model;
+using Microsoft.Extensions.Configuration;
+using SQL2Linked.Models.ConfigurationModels;
 using VDS.RDF;
 
-namespace SQL2Linked
+namespace SQL2Linked;
+
+/// <summary>
+/// Provides an abstract base class for handling structural data transformations and migrations.
+/// </summary>
+/// <typeparam name="S">The type of data to be transformed or migrated.</typeparam>
+/// <remarks>
+/// This class is partially shared between this script and the Trellis Migrator script.
+/// </remarks>
+public abstract class StructuralData<S>
 {
-    public abstract class StructuralData<S, T> where S : class where T : DatabaseModel<S>, new()
+    private readonly string _adminToken;
+    protected readonly Configuration _apiConfiguration;
+    protected readonly AdminApi _adminApi;
+    protected readonly PidConfiguration _pidConfiguration; // Comes from the API Client, not from the application's own configuration
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="StructuralData{S}"/> class.
+    /// </summary>
+    public StructuralData()
     {
-        public T Model { get; init; }
-        public ConsulConfiguration Configuration { get; init; }
-        public RdfStoreConnector RdfStoreConnector { get; init; }
-        public static string Prefix { get; set; }
+        // Retrieve the configuration settings for the PID ePIC API from the API Client
+        var apiConfiguration = ApiConfigurationUtil.RetrieveApiConfiguration();
+        _pidConfiguration = apiConfiguration.GetSection(PidConfiguration.Section).Get<PidConfiguration>() ?? new();
 
-        public StructuralData()
+        // Ensiure that the prefix is not null or empty.
+        ArgumentException.ThrowIfNullOrWhiteSpace(_pidConfiguration.Prefix, nameof(_pidConfiguration.Prefix));
+
+        // Generate an admin token for the API Client
+        var jwtConfiguration = ApiConfigurationUtil.RetrieveJwtConfiguration();
+        _adminToken = ApiConfigurationUtil.GenerateAdminToken(jwtConfiguration);
+        _apiConfiguration = new Configuration()
         {
-            Configuration = new ConsulConfiguration();
-            RdfStoreConnector = new RdfStoreConnector(Configuration.GetStringAndWait("coscine/local/virtuoso/additional/url"));
-            Model = new T();
-            Prefix = Configuration.GetStringAndWait("coscine/global/epic/prefix");
-            // 100 second timeout
-            var timeout = 100000;
-            RdfStoreConnector.QueryEndpoint.Timeout = timeout;
-            RdfStoreConnector.UpdateEndpoint.Timeout = timeout;
-            RdfStoreConnector.ReadWriteSparqlConnector.Timeout = timeout;
-        }
+            BasePath = "http://localhost:7206/coscine",
+            ApiKeyPrefix = { { "Authorization", "Bearer" } },
+            ApiKey = { { "Authorization", _adminToken } },
+        };
+        _adminApi = new AdminApi(_apiConfiguration);
+    }
 
-        public abstract IEnumerable<IGraph> ConvertToLinkedData(IEnumerable<S> entries);
+    /// <summary>
+    /// Converts the given entries to linked data graphs.
+    /// </summary>
+    /// <param name="entries">The entries to convert.</param>
+    /// <returns>An enumerable collection of graphs representing the linked data.</returns>
+    public abstract Task<IEnumerable<IGraph>> ConvertToLinkedDataAsync(IEnumerable<S> entries);
 
-        public virtual IEnumerable<S> GetAll()
-        {
-            return Model.GetAll();
-        }
+    /// <summary>
+    /// Retrieves all entries of type <typeparamref name="S"/>.
+    /// </summary>
+    /// <returns>A task that represents the asynchronous operation. The task result contains an enumerable of all entries.</returns>
+    public abstract Task<IEnumerable<S>> GetAll();
 
-        public void Migrate(bool dummyMode)
+    /// <summary>
+    /// Migrates the data, optionally in a dummy mode where changes are not persisted.
+    /// </summary>
+    /// <param name="dummyMode">If set to <c>true</c>, the migration is simulated but not executed.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    public async Task Migrate(bool dummyMode)
+    {
+        var spacer = new string('-', 35);
+        Console.WriteLine($"\n{spacer}\n{typeof(S).Name}\n{spacer}");
+        var graphs = await ConvertToLinkedDataAsync(await GetAll());
+        if (!dummyMode)
         {
-            var spacer = new string('-', 35);
-            Console.WriteLine($"\n{spacer}\n{typeof(T).Name}\n{spacer}");
-            var graphs = ConvertToLinkedData(GetAll());
-            if (!dummyMode)
-            {
-                StoreGraphs(graphs);
-            }
+            await StoreGraphs(graphs);
         }
+    }
 
-        public void StoreGraphs(IEnumerable<IGraph> graphs)
-        {
-            foreach (var graph in graphs)
-            {
-                try
-                {
-                    Console.WriteLine($" ({graph.BaseUri})");
-
-                    if (graph is WrapperGraph)
-                    {
-                        var wrapperGraph = (WrapperGraph)graph;
-                        // Chunking since the size otherwise can be too large
-                        foreach (var triples in wrapperGraph.AssertList.Chunk(100))
-                        {
-                            WrapRequest(() => RdfStoreConnector.ReadWriteSparqlConnector.UpdateGraph(graph.BaseUri, triples, new List<Triple>()));
-                        }
-                        // Chunking since the size otherwise can be too large
-                        foreach (var triples in wrapperGraph.RetractList.Chunk(100))
-                        {
-                            WrapRequest(() => RdfStoreConnector.ReadWriteSparqlConnector.UpdateGraph(graph.BaseUri, new List<Triple>(), triples));
-                        }
-                    }
-                    else
-                    {
-                        var exists = WrapRequest(() => RdfStoreConnector.HasGraph(graph.BaseUri));
-                        if (exists)
-                        {
-                            Console.WriteLine($" - Graph {graph.BaseUri} exists");
-
-                            // Clear the existing graph from the store
-                            WrapRequest(() => RdfStoreConnector.ClearGraph(graph.BaseUri));
-                            Console.WriteLine($" - Cleared Graph {graph.BaseUri}");
-                        }
-
-                        // Chunking since the size otherwise can be too large
-                        // Don't change to only addition of triples, otherwise this could break things
-                        foreach (var triples in graph.Triples.Chunk(100))
-                        {
-                            WrapRequest(() => RdfStoreConnector.ReadWriteSparqlConnector.UpdateGraph(graph.BaseUri, triples, new List<Triple>()));
-                        }
-                    }
-
-                    Console.WriteLine($" - Graph {graph.BaseUri} added successfully");
-                    Console.WriteLine();
-                }
-                catch (Exception e)
-                {
-                    Console.Error.WriteLine($"Error on ({graph.BaseUri}):");
-                    Console.Error.WriteLine(e);
-                    Console.Error.WriteLine(e.InnerException);
-                    Console.Error.WriteLine();
-                }
-            }
-        }
+    /// <summary>
+    /// Stores the given graphs in the underlying data store.
+    /// </summary>
+    /// <param name="graphs">The graphs to be stored.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    public async Task StoreGraphs(IEnumerable<IGraph> graphs)
+    {
+        var formatEnum = RdfFormat.TextTurtle;
+        var format = "text/turtle";
 
-        public void AssertToGraphUriNode(IGraph graph, string graphSubject, string graphPredicate, string? graphObject)
+        foreach (var graph in graphs)
         {
-            if (graphObject != null)
+            Console.WriteLine($" ({graph.BaseUri})");
+
+            try
             {
-                graph.Assert(
-                    new Triple(
-                        graph.CreateUriNode(new Uri(graphSubject)),
-                        graph.CreateUriNode(new Uri(graphPredicate)),
-                        graph.CreateUriNode(new Uri(graphObject))
-                    )
+                var rdfWriter = MimeTypesHelper.GetWriter(format);
+                var content = VDS.RDF.Writing.StringWriter.Write(graph, rdfWriter);
+
+                await _adminApi.UpdateMetadataGraphAsync(
+                    graph.BaseUri.AbsoluteUri,
+                    new MetadataUpdateAdminParameters(new RdfDefinitionForManipulationDto(content, formatEnum))
                 );
-            }
-        }
 
-        public void AssertToGraphLiteralNode(IGraph graph, string graphSubject, string graphPredicate, string? graphObject, Uri? objectType = null)
-        {
-            if (graphObject != null)
+                Console.WriteLine($" - Graph {graph.BaseUri} added successfully");
+                Console.WriteLine();
+            }
+            catch (Exception e)
             {
-                graph.Assert(
-                    new Triple(
-                        graph.CreateUriNode(new Uri(graphSubject)),
-                        graph.CreateUriNode(new Uri(graphPredicate)),
-                        graph.CreateLiteralNode(graphObject, objectType)
-                    )
-                );
+                Console.Error.WriteLine($"Error on ({graph.BaseUri}):");
+                Console.Error.WriteLine(e);
+                Console.Error.WriteLine(e.InnerException);
+                Console.Error.WriteLine();
             }
         }
+    }
 
-        public void AssertToGraphBlankAndUriNode(IGraph graph, IBlankNode graphSubject, string graphPredicate, string? graphObject)
+    /// <summary>
+    /// Asserts a triple to the graph with a URI node object.
+    /// </summary>
+    /// <param name="graph">The graph to assert to.</param>
+    /// <param name="graphSubject">The subject URI of the triple.</param>
+    /// <param name="graphPredicate">The predicate URI of the triple.</param>
+    /// <param name="graphObject">The object URI of the triple.</param>
+    public void AssertToGraphUriNode(IGraph graph, Uri graphSubject, Uri graphPredicate, Uri? graphObject)
+    {
+        if (graphObject != null)
         {
-            if (graphObject != null)
-            {
-                graph.Assert(
-                    new Triple(
-                        graphSubject,
-                        graph.CreateUriNode(new Uri(graphPredicate)),
-                        graph.CreateUriNode(new Uri(graphObject))
-                    )
-                );
-            }
+            graph.Assert(
+                new Triple(
+                    graph.CreateUriNode(graphSubject),
+                    graph.CreateUriNode(graphPredicate),
+                    graph.CreateUriNode(graphObject)
+                )
+            );
         }
+    }
 
-        /// <summary>
-        /// Retry Virtuoso Requests since they sometimes just fail
-        /// </summary>
-        /// <typeparam name="W"></typeparam>
-        /// <param name="function"></param>
-        /// <returns></returns>
-        public void WrapRequest(Action action)
+    /// <summary>
+    /// Asserts a triple to the graph with a literal node object.
+    /// </summary>
+    /// <param name="graph">The graph to assert to.</param>
+    /// <param name="graphSubject">The subject URI of the triple.</param>
+    /// <param name="graphPredicate">The predicate URI of the triple.</param>
+    /// <param name="graphObject">The literal object of the triple.</param>
+    /// <param name="objectType">The data type URI of the literal object, if any.</param>
+    public void AssertToGraphLiteralNode(IGraph graph, Uri graphSubject, Uri graphPredicate, string? graphObject, Uri? objectType = null)
+    {
+        if (graphObject != null)
         {
-            Policy
-                .Handle<Exception>()
-                .WaitAndRetry(5, retryNumber => TimeSpan.FromMilliseconds(200))
-                .Execute(() => action.Invoke());
+            graph.Assert(
+                new Triple(
+                    graph.CreateUriNode(graphSubject),
+                    graph.CreateUriNode(graphPredicate),
+                    objectType is not null ? graph.CreateLiteralNode(graphObject, objectType) : graph.CreateLiteralNode(graphObject)
+                )
+            );
         }
+    }
 
-        /// <summary>
-        /// Retry Virtuoso Requests since they sometimes just fail
-        /// </summary>
-        /// <typeparam name="W"></typeparam>
-        /// <param name="function"></param>
-        /// <returns></returns>
-        public W WrapRequest<W>(Func<W> function)
+    /// <summary>
+    /// Asserts a triple to the graph with a blank node subject and a URI node object.
+    /// </summary>
+    /// <param name="graph">The graph to assert to.</param>
+    /// <param name="graphSubject">The blank node subject of the triple.</param>
+    /// <param name="graphPredicate">The predicate URI of the triple.</param>
+    /// <param name="graphObject">The object URI of the triple.</param>
+    public void AssertToGraphBlankAndUriNode(IGraph graph, IBlankNode graphSubject, Uri graphPredicate, Uri? graphObject)
+    {
+        if (graphObject != null)
         {
-            return Policy
-                .Handle<Exception>()
-                .WaitAndRetry(5, retryNumber => TimeSpan.FromMilliseconds(200))
-                .ExecuteAndCapture(() => function.Invoke()).Result;
+            graph.Assert(
+                new Triple(
+                    graphSubject,
+                    graph.CreateUriNode(graphPredicate),
+                    graph.CreateUriNode(graphObject)
+                )
+            );
         }
     }
 }
diff --git a/src/SQL2Linked/Utils/RdfUris.cs b/src/SQL2Linked/Utils/RdfUris.cs
new file mode 100644
index 0000000..e5b1dd4
--- /dev/null
+++ b/src/SQL2Linked/Utils/RdfUris.cs
@@ -0,0 +1,215 @@
+// Ignore Spelling: Foaf Dcat Dcterms Ebocore Fdp Ldp Xsd
+
+/// ------------------
+/// TAKEN FROM THE API
+/// ------------------
+
+namespace SQL2Linked.Utils;
+
+/// <summary>
+/// Contains URIs relevant to RDF (Resource Description Framework) and related schemas/ontologies.
+/// </summary>
+public static class RdfUris
+{
+    // ACL
+    public static readonly Uri AclPrefix = new("http://www.w3.org/ns/auth/acl#");
+
+    public static readonly Uri AclAccessTo = new("http://www.w3.org/ns/auth/acl#accessTo");
+    public static readonly Uri AclAgentGroup = new("http://www.w3.org/ns/auth/acl#agentGroup");
+    public static readonly Uri AclDefault = new("http://www.w3.org/ns/auth/acl#default");
+    public static readonly Uri AclMode = new("http://www.w3.org/ns/auth/acl#mode");
+
+    public static readonly Uri AclAuthorizationClass = new("http://www.w3.org/ns/auth/acl#Authorization");
+    public static readonly Uri AclReadClass = new("http://www.w3.org/ns/auth/acl#Read");
+    public static readonly Uri AclWriteClass = new("http://www.w3.org/ns/auth/acl#Write");
+
+    // Coscine
+    public static readonly Uri CoscinePrefix = new("https://purl.org/coscine/");
+
+    public static readonly Uri CoscineApplicationProfile = new("https://purl.org/coscine/ap/");
+    public static readonly Uri CoscineFixedValue = new("https://purl.org/coscine/fixedValue");
+    public static readonly Uri CoscineMetadataExtractionVersion = new("https://purl.org/coscine/terms/metatadataextraction#version");
+    public static readonly Uri CoscineProjects = new("https://purl.org/coscine/projects/");
+    public static readonly Uri CoscineResourceTypes = new("https://purl.org/coscine/resourcetypes/");
+    public static readonly Uri CoscineResources = new("https://purl.org/coscine/resources/");
+    public static readonly Uri CoscineRoles = new("https://purl.org/coscine/roles/");
+    public static readonly Uri CoscineUsers = new("https://purl.org/coscine/users/");
+
+    [Obsolete($"Beware the side-effects before changing! Use {nameof(CoscineUsers)} instead.")]
+    public static readonly Uri CoscineUserLegacy = new("https://coscine.rwth-aachen.de/u/");
+
+    // Coscine Terms
+    public static readonly Uri CoscineTermsPrefix = new("https://purl.org/coscine/terms/");
+
+    public static readonly Uri CoscineTermsLinkedBody = new("https://purl.org/coscine/terms/linked#body");
+    public static readonly Uri CoscineTermsMetadataTrackerAgent = new("https://purl.org/coscine/terms/metadatatracker#Agent");
+    public static readonly Uri CoscineTermsProject = new("https://purl.org/coscine/terms/project#");
+    public static readonly Uri CoscineTermsProjectDeleted = new("https://purl.org/coscine/terms/project#deleted");
+    public static readonly Uri CoscineTermsProjectSlug = new("https://purl.org/coscine/terms/project#slug");
+    public static readonly Uri CoscineTermsProjectVisibility = new("https://purl.org/coscine/terms/project#visibility");
+    public static readonly Uri CoscineTermsResource = new("https://purl.org/coscine/terms/resource#");
+    public static readonly Uri CoscineTermsResourceArchived = new("https://purl.org/coscine/terms/resource#archived");
+    public static readonly Uri CoscineTermsResourceDeleted = new("https://purl.org/coscine/terms/resource#deleted");
+    public static readonly Uri CoscineTermsResourceFixedValues = new("https://purl.org/coscine/terms/resource#fixedValues");
+    public static readonly Uri CoscineTermsResourceVisibility = new("https://purl.org/coscine/terms/resource#visibility");
+    public static readonly Uri CoscineTermsTypes = new("https://purl.org/coscine/terms/types#");
+    public static readonly Uri CoscineTermsUserAgent = new("https://purl.org/coscine/terms/user#Agent");
+    public static readonly Uri CoscineTermsVisibility = new("https://purl.org/coscine/terms/visibility#");
+    public static readonly Uri CoscineTermsVisibilityPublic = new("https://purl.org/coscine/terms/visibility#public");
+    public static readonly Uri CoscineTermsVisibilityProjectMember = new("https://purl.org/coscine/terms/visibility#projectMember");
+    public static readonly Uri CoscineTermsRole = new("https://purl.org/coscine/terms/role#");
+
+    // CSMD
+    public static readonly Uri CsmdPrefix = new("http://www.purl.org/net/CSMD/4.0#");
+
+    // DCAT
+    public static readonly Uri DcatPrefix = new("http://www.w3.org/ns/dcat#");
+
+    public static readonly Uri DcatCatalog = new("http://www.w3.org/ns/dcat#catalog");
+    public static readonly Uri DcatDataset = new("http://www.w3.org/ns/dcat#dataset");
+    public static readonly Uri DcatDistribution = new("http://www.w3.org/ns/dcat#distribution");
+    public static readonly Uri DcatService = new("http://www.w3.org/ns/dcat#service");
+
+    public static readonly Uri DcatCatalogClass = new("http://www.w3.org/ns/dcat#Catalog");
+    public static readonly Uri DcatDataServiceClass = new("http://www.w3.org/ns/dcat#DataService");
+    public static readonly Uri DcatDatasetClass = new("http://www.w3.org/ns/dcat#Dataset");
+
+    // DCMI Type
+    public static readonly Uri DcmiTypePrefix = new("http://purl.org/dc/dcmitype/");
+
+    // DC
+    public static readonly Uri DcPrefix = new("http://purl.org/dc/elements/1.1/");
+
+    // DC Terms
+    public static readonly Uri DcTermsPrefix = new("http://purl.org/dc/terms/");
+
+    public static readonly Uri DcTermsAlternative = new("http://purl.org/dc/terms/alternative");
+    public static readonly Uri DcTermsConformsTo = new("http://purl.org/dc/terms/conformsTo");
+    public static readonly Uri DcTermsCreator = new("http://purl.org/dc/terms/creator");
+    public static readonly Uri DcTermsCreated = new("http://purl.org/dc/terms/created");
+    public static readonly Uri DcTermsDescription = new("http://purl.org/dc/terms/description");
+    public static readonly Uri DcTermsEndDate = new("http://purl.org/dc/terms/endDate");
+    public static readonly Uri DcTermsIdentifier = new("http://purl.org/dc/terms/identifier");
+    public static readonly Uri DcTermsIsPartOf = new("http://purl.org/dc/terms/isPartOf");
+    public static readonly Uri DcTermsLicense = new("http://purl.org/dc/terms/license");
+    public static readonly Uri DcTermsModified = new("http://purl.org/dc/terms/modified");
+    public static readonly Uri DcTermsRights = new("http://purl.org/dc/terms/rights");
+    public static readonly Uri DcTermsRightsHolder = new("http://purl.org/dc/terms/rightsHolder");
+    public static readonly Uri DcTermsStartDate = new("http://purl.org/dc/terms/startDate");
+    public static readonly Uri DcTermsSubject = new("http://purl.org/dc/terms/subject");
+    public static readonly Uri DcTermsTitle = new("http://purl.org/dc/terms/title");
+
+    // EBUCORE
+    public static readonly Uri EbocorePrefix = new("http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#");
+
+    public static readonly Uri EbocoreHashFunction = new("http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#hashFunction");
+    public static readonly Uri EbocoreHashType = new("http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#hashType");
+    public static readonly Uri EbocoreHashValue = new("http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#hashValue");
+
+    // FDP
+    public static readonly Uri FdpPrefix = new("http://purl.org/fdp/fdp-o#");
+
+    public static readonly Uri FdpHasMetadata = new("http://purl.org/fdp/fdp-o#hasMetadata");
+    public static readonly Uri FdpIsMetadataOf = new("http://purl.org/fdp/fdp-o#isMetadataOf");
+
+    public static readonly Uri FdpMetadataServiceClass = new("http://purl.org/fdp/fdp-o#MetadataService");
+
+    // FOAF
+    public static readonly Uri FoafPrefix = new("http://xmlns.com/foaf/0.1/");
+
+    public static readonly Uri FoafHomepage = new("http://xmlns.com/foaf/0.1/homepage");
+    public static readonly Uri FoafName = new("http://xmlns.com/foaf/0.1/name");
+
+    public static readonly Uri FoafPersonClass = new("http://xmlns.com/foaf/0.1/Person");
+
+    // Handle
+    public static readonly Uri HandlePrefix = new("https://hdl.handle.net/");
+
+    // LDP
+    public static readonly Uri LdpPrefix = new("http://www.w3.org/ns/ldp#");
+
+    public static readonly Uri LdpDescribedBy = new("http://www.w3.org/ns/ldp#describedBy");
+
+    public static readonly Uri LdpBasicContainerClass = new("http://www.w3.org/ns/ldp#BasicContainer");
+    public static readonly Uri LdpNonRDFSourceClass = new("http://www.w3.org/ns/ldp#NonRDFSource");
+    public static readonly Uri LdpRDFSourceClass = new("http://www.w3.org/ns/ldp#RDFSource");
+
+    // ORG
+    public static readonly Uri OrgPrefix = new("http://www.w3.org/ns/org#");
+
+    public static readonly Uri OrgMember = new("http://www.w3.org/ns/org#member");
+    public static readonly Uri OrgOrganization = new("http://www.w3.org/ns/org#organization");
+    public static readonly Uri OrgRole = new("http://www.w3.org/ns/org#role");
+
+    public static readonly Uri OrgMembershipClass = new("http://www.w3.org/ns/org#Membership");
+    public static readonly Uri OrgOrganizationalCollaborationClass = new("http://www.w3.org/ns/org#OrganizationalCollaboration");
+    public static readonly Uri OrgRoleClass = new("http://www.w3.org/ns/org#Role");
+
+    // OWL
+    public static readonly Uri OwlPrefix = new("http://www.w3.org/2002/07/owl#");
+
+    public static readonly Uri OwlImports = new("http://www.w3.org/2002/07/owl#imports");
+
+    // PIM
+    public static readonly Uri PimPrefix = new("http://www.w3.org/ns/pim/space#");
+
+    public static readonly Uri PimStorageClass = new("http://www.w3.org/ns/pim/space#Storage");
+
+    // PROV
+    public static readonly Uri ProvPrefix = new("http://www.w3.org/ns/prov#");
+
+    public static readonly Uri ProvEntityClass = new("http://www.w3.org/ns/prov#Entity");
+
+    public static readonly Uri ProvGeneratedAtTime = new("http://www.w3.org/ns/prov#generatedAtTime");
+    public static readonly Uri ProvWasInvalidatedBy = new("http://www.w3.org/ns/prov#wasInvalidatedBy");
+    public static readonly Uri ProvWasRevisionOf = new("http://www.w3.org/ns/prov#wasRevisionOf");
+
+    // RDF
+    public static readonly Uri RdfUrlPrefix = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+
+    public static readonly Uri A = new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+
+    // RDFS
+    public static readonly Uri RdfsUrlPrefix = new("http://www.w3.org/2000/01/rdf-schema#");
+
+    public static readonly Uri SubClassOf = new("http://www.w3.org/2000/01/rdf-schema#subClassOf");
+
+    // ROR IDs
+    /// <summary>
+    /// Represents the RWTH Aachen's ROR (Research Organization Registry) ID.
+    /// </summary>
+    public static readonly Uri RwthRorId = new("https://ror.org/04xfq0f34");
+
+    // SCHEMA
+    public static readonly Uri SchemaPrefix = new("http://schema.org/");
+
+    public static readonly Uri SchemaFunding = new("http://schema.org/funding");
+
+    // SHACL
+    public static readonly Uri ShaclPrefix = new("http://www.w3.org/ns/shacl#");
+
+    public static readonly Uri ShaclDatatype = new("http://www.w3.org/ns/shacl#datatype");
+    public static readonly Uri ShaclPath = new("http://www.w3.org/ns/shacl#path");
+    public static readonly Uri ShaclProperty = new("http://www.w3.org/ns/shacl#property");
+    public static readonly Uri ShaclTargetClass = new("http://www.w3.org/ns/shacl#targetClass");
+    public static readonly Uri Class = new("http://www.w3.org/ns/shacl#class");
+
+    // Trellis
+    public static readonly Uri TrellisPrefix = new("http://www.trellisldp.org/ns/trellis#");
+
+    public static readonly Uri TrellisGraph = new("http://www.trellisldp.org/ns/trellis#PreferServerManaged");
+
+    // Vcard
+    public static readonly Uri VcardPrefix = new("http://www.w3.org/2006/vcard/ns#");
+
+    public static readonly Uri VcardHasMember = new("http://www.w3.org/2006/vcard/ns#hasMember");
+
+    public static readonly Uri VcardGroupClass = new("http://www.w3.org/2006/vcard/ns#Group");
+
+    // XSD
+    public static readonly Uri XsdPrefix = new("http://www.w3.org/2001/XMLSchema#");
+
+    public static readonly Uri XsdDateTime = new("http://www.w3.org/2001/XMLSchema#dateTime");
+    public static readonly Uri XsdBoolean = new("http://www.w3.org/2001/XMLSchema#boolean");
+    public static readonly Uri XsdHexBinary = new("http://www.w3.org/2001/XMLSchema#hexBinary");
+}
\ No newline at end of file
diff --git a/src/SQL2Linked/Utils/UriHelper.cs b/src/SQL2Linked/Utils/UriHelper.cs
new file mode 100644
index 0000000..e0e8f06
--- /dev/null
+++ b/src/SQL2Linked/Utils/UriHelper.cs
@@ -0,0 +1,31 @@
+namespace SQL2Linked.Utils;
+
+/// <summary>
+/// 
+/// </summary>
+public static class UriHelper
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="baseUri"></param>
+    /// <param name="relativePath"></param>
+    /// <returns></returns>
+    public static Uri? TryCombineUri(Uri baseUri, string relativePath)
+    {
+        Uri.TryCreate(baseUri, relativePath, out Uri? result);
+        return result;
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="baseUri"></param>
+    /// <param name="relativePath"></param>
+    /// <returns></returns>
+    public static Uri? TryCombineUri(Uri baseUri, Guid relativePath)
+    {
+        Uri.TryCreate(baseUri, relativePath.ToString(), out Uri? result);
+        return result;
+    }
+}
diff --git a/src/SQL2Linked/WrapperGraph.cs b/src/SQL2Linked/WrapperGraph.cs
deleted file mode 100644
index ce318c3..0000000
--- a/src/SQL2Linked/WrapperGraph.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using VDS.RDF;
-
-namespace SQL2Linked
-{
-    public class WrapperGraph : Graph
-    {
-        public List<Triple> AssertList { get; set; }
-        public List<Triple> RetractList { get; set; }
-
-        public WrapperGraph() : base()
-        {
-            AssertList = new List<Triple>();
-            RetractList = new List<Triple>();
-        }
-
-        public override bool Assert(Triple t)
-        {
-            AssertList.Add(t);
-            return base.Assert(t);
-        }
-
-        public override bool Assert(IEnumerable<Triple> triples)
-        {
-            AssertList.AddRange(triples);
-            return base.Assert(triples);
-        }
-
-        public override bool Retract(Triple t)
-        {
-            RetractList.Add(t);
-            return base.Retract(t);
-        }
-
-        public override bool Retract(IEnumerable<Triple> triples)
-        {
-            RetractList.AddRange(triples);
-            return base.Retract(triples);
-        }
-    }
-}
-- 
GitLab