GraphQL:和EntityFramework更配哦

GraphQL 既是一種用於 API 的查詢語言也是一個滿足你數據查詢的運行時。GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的數據,而且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。

                                                          ——出自 https://graphql.cn

對於查詢,更多的時候,數據是在結構化數據庫中,API服務通過ORM實現查詢數據庫,並且API以不同的url提供給外部調用;試想,我們如果通過ado.net來訪問數據庫的話,對於GraphQL的靈活查詢方式,我們怎麼通過一條語句完全適配?這是個難點,只能把全部的數據集查詢出來,讓graphql在內存篩選自己所需要的數據,這樣的話,大量數據的集合很快就會把內存佔完的,不可取,當然像dapper這種直接寫sql的方式就不行了。
這時,EF的優勢就顯露出來了,其實EF本身是給後臺程序員使用,封裝了一組Linq表達式轉sql的功能,這樣後臺程序員就不用關心sql語句了;這裏,如果能把GraphQL和Linq打通,就可以實現GraphQL接口,後臺開發也變的簡單了;正好,天作一對,GraphQL碰上了EF,使兩者變的“天衣無縫”。

Michael Staib也是這麼做的,並且帶來了HotChocolate,下面是一個GraphQL+EF(sql server)的案例。

添加Nuget包

HotChocolate.AspNetCore
HotChocolate.Data
HotChocolate.Data.EntityFramework


using HotChocolate;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace GraphQLDemo01
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddPooledDbContextFactory<AdventureWorks2016Context>(
                (services, options) => options
                .UseSqlServer(Configuration.GetConnectionString("ConnectionString"))
                .UseLoggerFactory(services.GetRequiredService<ILoggerFactory>()))
                .AddGraphQLServer()
                .AddQueryType<Query>()
                .AddFiltering()
                .AddSorting()
                .AddProjections();
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGraphQL();
            });
        }
    }
}

案例數據庫是用的sql server官方的demo數據庫AdventureWorks,每個查詢方法變的非常簡單,只需要把對應實體集合返回即可,但返回值一定是IQueryabl<>,正是這個特點,讓GraphQL與EF變的這麼貼合。特性上增加了一個分頁,考慮到數據量大,HotChocolate很貼心的帶了分頁。AdventureWorks生成的實體類和Context就不作顯示了。


using System.Linq;
using HotChocolate;
using HotChocolate.Data;
using HotChocolate.Types;
namespace GraphQLDemo01
{
    public class Query
    {
        [UseDbContext(typeof(AdventureWorks2016Context))]
        [UseOffsetPaging]
        [UseProjection]
        [UseFiltering]
        [UseSorting]
        public IQueryable<Product> GetProducts([ScopedService] AdventureWorks2016Context context)
        {
            return context.Products;
        }

        [UseDbContext(typeof(AdventureWorks2016Context))]
        [UsePaging]
        [UseProjection]
        [UseFiltering]
        [UseSorting]
        public IQueryable<Person> GetPersons([ScopedService] AdventureWorks2016Context context)
        {
            return context.People;
        }
    }
}

使用查詢色彩爲紅色的產品,並且按listPrice排序


{
   products(where: { color:{  eq:"Red"}   } order:[{listPrice:ASC}]) {
       items{
            productId
            name
            listPrice
       }
     }
 }

分頁(UsePaging)查詢person


{
   persons( order: [{ businessEntityId: ASC }] after:"MTk="){
      pageInfo{
        hasNextPage
        hasPreviousPage
        startCursor
        endCursor
      }
      nodes{
         businessEntityId
         firstName
         middleName
         lastName
         emailAddresses{
            emailAddressId
            emailAddress1
            modifiedDate
         }
      }
      edges{
         cursor
         node{
            businessEntityId
         }
      }
     }     
 }

分頁(UseOffsetPaging)查詢產品


{
   products( order: [{ productId: ASC }] skip:40 take:20){
      pageInfo{
        hasNextPage
        hasPreviousPage    
      }
      items{
         productId
         name
      }
   }     
 }

這些查詢如果你跟蹤sql語句的話,會發現生成的sql會限制查詢範圍,這樣就能提高內存的使用率,當然這個功勞在EF,並不是GraphQL所要做的事,這也是ado.net和dapper類的ORM與GraphQL般配的原因。

相同的GrapQL,下圖是dapper查詢Product表的語句。
GraphQL:和EntityFramework更配哦

下圖是EF生成的語句,EF生成的語句更精確。
GraphQL:和EntityFramework更配哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章