Виконання запитів GraphQL з допомогою OdataToEntity


У статті розповідається як транслювати запити GraphQL в OData і виконувати їх написавши
зовсім трохи коду на C#.

 

Як це працює

 

Основна ідея проекту — трансляція запитів GraphQL в OData, трансляція запитів OData в дерево виразів, яке потім транслюється в запит для ORM. Розбір запиту GraphQL і серіалізація його результатів здійснюється за допомогою GraphQL for .NET. Розбір запиту OData здійснюється з допомогою OData .NET Libraries. Трансляція запитів (GraphQL -> OData -> expression tree) і їх виконання здійснюється за допомогою OdataToEntity.

 

Безпосередній доступ до даних здійснюється через ORM виконує отримане дерево вирази (expression tree). Виконання запитів на різних ORM здійснюється через абстрактний клас OeDataAdapter і його реалізації для:

 

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

 

Від користувача потрібно лише мати контекст доступу до даних (EF/EF Core — DbContext, Linq2Db — DataConnection).
Більш докладно про виконання запитів OData можна прочитати у моїй попередній статті OdataToEntity легкий спосіб створення .Net Core OData сервісів.

 

Приклад використання
Для прикладу буде використовуватися схема Star Wars, ORM EF Core, провайдер SQLite in memory.

 

Спочатку треба створити контекст доступу до даних 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(dataAdapter, 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": "ДЖЕДАЇВ"
}
]
},
{
 "name": "C-3PO",
 "appearsIn": [
{
 "name": "NEWHOPE"
},
{
 "name": "EMPIRE"
},
{
 "name": "ДЖЕДАЇВ"
}
]
}
]
}
]
}
}

 

Генерований SQL не має проблеми N+1 запитів, всі дані виходять в одному запиті.

 

Структура вихідного коду
Вихідний код розділений на дві частини: в папці source — сама бібліотека і складання доступу до різних джерел даних, в папці test — тести і приклади коду.
Сама бібліотека знаходиться в папці source/OdataEntity.GraphQL.
Тести test/OdataToEntity.Test.GraphQL.
Файл солюшена sln/OdataToEntity.Test.GraphQL.sln.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *