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更配哦

 

 

  想要更快更方便的了解相关知识,可以关注微信公众号    GraphQL:和EntityFramework更配哦

 

 

上一篇:GraphQL:简单开开始一个查询


下一篇:GraphQL:验证与授权