この記事では、GraphQLクエリをODataに変換し、記述して実行する方法について説明します
かなりのC#コード。
仕組み
このプロジェクトの主なアイデアは、GraphQLクエリをODataに変換し、ODataクエリを式ツリーに変換し、それをORMのクエリに変換することです。 GraphQLクエリの解析と結果のシリアル化は、 GraphQL for .NETを使用して行われます 。 ODataクエリ解析は、 OData .NET Librariesを使用して行われます 。 クエリの変換(GraphQL-> OData->式ツリー)とその実行はOdataToEntityを使用して実行されます。
データへの直接アクセスは、結果の式ツリーを実行するORMを介して実行されます。 さまざまなORMのクエリは、次の抽象クラスOeDataAdapterとその実装を通じて実行されます。
- Entity Framework OeEf6DataAdapter
- Entity Framework Core OeEfCoreDataAdapter
- Linq2Db OeLinq2DbDataAdapter
ユーザーは、データアクセスコンテキスト(EF / EF Core-DbContext、Linq2Db-DataConnection)のみを持っている必要があります。
ODataクエリの実行の詳細については、以前の記事OdataToEntityをご覧ください。 これは、.Net Core ODataサービスを簡単に作成する方法です。
使用例
たとえば、メモリプロバイダーのSQLiteであるスターウォーズスキーマORM EF Coreを使用します。
まず、 StarWarsContextデータアクセスコンテキストを作成する必要があります。 次に、 StarWarsDataAdapterデータアクセスアダプター。 リクエストの実行を開始した後:
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クエリ:
{ human(id: ""1"") { name friends { name appearsIn { name } } } }
ODataに翻訳:
Human?$filter=Id eq '1'&$select=Name&$expand=Friends($select=Name;$expand=AppearsIn($select=Name))
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結果:
{ "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" } ] } ] } ] } }
生成されたSQLにはN + 1クエリの問題はなく、すべてのデータが1つのクエリで受信されます。
ソースコード構造
ソースコードは2つの部分に分かれています: ソースフォルダー-ライブラリ自体と、さまざまなデータソースのアセンブリ、 テストフォルダー-テストとコード例。
ライブラリ自体は、 source / OdataEntity.GraphQLフォルダーにあります 。
test / OdataToEntity.Test.GraphQLをテストします。
ソリューションファイルsln / OdataToEntity.Test.GraphQL.sln 。