Ausführen von GraphQL-Abfragen mit OdataToEntity


Der Artikel beschreibt, wie Sie GraphQL-Abfragen in OData übersetzen und durch Schreiben ausführen
ziemlich viel C # -Code.


Wie funktioniert es?


Die Hauptidee des Projekts ist die Übersetzung von GraphQL-Abfragen in OData, die Übersetzung von OData-Abfragen in einen Ausdrucksbaum, der dann in eine Abfrage für ORM übersetzt wird. Das Parsen einer GraphQL-Abfrage und das Serialisieren ihrer Ergebnisse erfolgt mit GraphQL für .NET . Das Parsen von OData-Abfragen erfolgt mithilfe von OData .NET-Bibliotheken . Die Abfrageübersetzung (GraphQL -> OData -> Ausdrucksbaum) und ihre Ausführung erfolgt mit OdataToEntity .


Der direkte Zugriff auf Daten erfolgt über das ORM, das den resultierenden Ausdrucksbaum ausführt. Abfragen auf verschiedenen ORMs werden über die abstrakte Klasse OeDataAdapter und deren Implementierung ausgeführt für:


  1. Entity Framework OeEf6DataAdapter
  2. Entity Framework Core OeEfCoreDataAdapter
  3. Linq2Db OeLinq2DbDataAdapter

Der Benutzer muss nur über einen Datenzugriffskontext verfügen (EF / EF Core - DbContext, Linq2Db - DataConnection).
Weitere Informationen zum Ausführen von OData-Abfragen finden Sie in meinem vorherigen Artikel OdataToEntity, einer einfachen Methode zum Erstellen von .Net Core OData-Diensten .


Anwendungsbeispiel


Zum Beispiel werden wir das Star Wars- Schema ORM EF Core verwenden, den SQLite in Memory-Anbieter.


Zuerst müssen Sie einen StarWarsContext- Datenzugriffskontext erstellen. Dann der StarWarsDataAdapter -Datenzugriffsadapter. Nachdem Sie mit der Ausführung der Anforderung beginnen können:


String query = @" { human(id: ""1"") { name friends { name appearsIn { name } } } } "; //create data adapter var dataAdapter = new StarWars.StarWarsDataAdapter(false, "test"); //build odata model IEdmModel edmModel = dataAdapter.BuildEdmModelFromEfCoreModel(); //create graphql query parser var parser = new OeGraphqlParser(edmModel); //get graphql result ExecutionResult result = await parser.Execute(query); //serialize json String json = new DocumentWriter(true).Write(result); Console.WriteLine(json); 

GraphQL-Abfrage:


 { human(id: ""1"") { name friends { name appearsIn { name } } } } 

Übersetzt in OData:


 Human?$filter=Id eq '1'&$select=Name&$expand=Friends($select=Name;$expand=AppearsIn($select=Name)) 

Übersetzt in SQL:


 SELECT "h"."Name" AS "Item1", "h"."Id" AS "Item2", CASE WHEN "t"."Id" IS NULL THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END, "t"."Name" AS "Item10", "t"."Id" AS "Item20", CASE WHEN "EpisodeEnum"."Value" IS NULL THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END, "EpisodeEnum"."Name" AS "Item11", "EpisodeEnum"."Value" AS "Item21" FROM "Hero" AS "h" LEFT JOIN "HeroToHero" AS "CharacterToCharacter" ON "h"."Id" = "CharacterToCharacter"."CharacterId" LEFT JOIN ( SELECT "Hero".* FROM "Hero" AS "Hero" WHERE "Hero"."CharacterType" IN (1, 2) ) AS "t" ON "CharacterToCharacter"."FriendId" = "t"."Id" LEFT JOIN "HeroToEpisode" AS "CharacterToEpisode" ON "t"."Id" = "CharacterToEpisode"."CharacterId" LEFT JOIN "Episodes" AS "EpisodeEnum" ON "CharacterToEpisode"."EpisodeId" = "EpisodeEnum"."Value" WHERE ("h"."CharacterType" = 1) AND ("h"."Id" = @__Item1_0) 

JSON-Ergebnis:


 { "data": { "human": [ { "name": "Luke", "friends": [ { "name": "R2-D2", "appearsIn": [ { "name": "NEWHOPE" }, { "name": "EMPIRE" }, { "name": "JEDI" } ] }, { "name": "C-3PO", "appearsIn": [ { "name": "NEWHOPE" }, { "name": "EMPIRE" }, { "name": "JEDI" } ] } ] } ] } } 

Generiertes SQL hat kein Problem mit N + 1-Abfragen. Alle Daten werden in einer Abfrage abgerufen.


Quellcodestruktur


Der Quellcode ist in zwei Teile unterteilt: im Quellordner - der Bibliothek selbst und Zugriff auf Assemblys auf verschiedene Datenquellen, im Testordner - Tests und Codebeispiele.
Die Bibliothek selbst befindet sich im Ordner source / OdataEntity.GraphQL .
Testet test / OdataToEntity.Test.GraphQL .
Die Lösungsdatei sln / OdataToEntity.Test.GraphQL.sln .

Source: https://habr.com/ru/post/de429088/


All Articles