
O artigo descreve como converter consultas GraphQL em OData e executá-las escrevendo
bastante código C #.
Como isso funciona
A idéia principal do projeto é a tradução de consultas GraphQL em OData, a tradução de consultas OData em uma árvore de expressão, que é então traduzida em uma consulta para ORM. A análise de uma consulta GraphQL e a serialização de seus resultados são feitas usando o GraphQL for .NET . A análise de consultas OData é feita usando as Bibliotecas OData .NET . A conversão de consultas (GraphQL -> OData -> árvore de expressão) e sua execução são realizadas usando OdataToEntity .
O acesso direto aos dados é realizado através do ORM que executa a árvore de expressão resultante. As consultas em vários ORMs são executadas através da classe abstrata OeDataAdapter e sua implementação para:
- Estrutura de entidades OeEf6DataAdapter
- Entity Framework Core OeEfCoreDataAdapter
- Linq2Db OeLinq2DbDataAdapter
O usuário precisa apenas ter um contexto de acesso a dados (EF / EF Core - DbContext, Linq2Db - DataConnection).
Você pode ler mais sobre a execução de consultas OData no meu artigo anterior, OdataToEntity, uma maneira fácil de criar serviços .Net Core OData .
Exemplo de uso
Por exemplo, usaremos o esquema Star Wars , ORM EF Core, o SQLite no provedor de memória.
Primeiro, você precisa criar um contexto de acesso a dados StarWarsContext . Em seguida, o adaptador de acesso a dados StarWarsDataAdapter . Depois que você pode começar a executar a solicitação:
String query = @" { human(id: ""1"") { name friends { name appearsIn { name } } } } ";
Consulta GraphQL:
{ human(id: ""1"") { name friends { name appearsIn { name } } } }
Traduzido para OData:
Human?$filter=Id eq '1'&$select=Name&$expand=Friends($select=Name;$expand=AppearsIn($select=Name))
Traduzido para 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)
Resultado 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" } ] } ] } ] } }
O SQL gerado não tem um problema de consultas N + 1, todos os dados são obtidos em uma consulta.
Estrutura do código fonte
O código fonte é dividido em duas partes: na pasta de origem - a própria biblioteca e acessa os assemblies para várias fontes de dados, na pasta de teste - testes e exemplos de código.
A própria biblioteca está localizada na pasta source / OdataEntity.GraphQL .
Testa test / OdataToEntity.Test.GraphQL .
O arquivo de solução sln / OdataToEntity.Test.GraphQL.sln .