.NET中SQL数据库的GraphQL API

您可能已经阅读了大量关于GraphQL的文章,并且已经了解了这种API技术的所有优缺点,作为REST API的替代方案。但是,让我们不久回顾一下GraphQL是什么,它的主要目的,以及我们如何在现实生活中使用它。

关于GraphQL的简短信息

GraphQL于2015年由Facebook发布,定位为着名的RESTful架构风格的替代品。您只有一个Web API端点,而不是数百个Web API方法(显然可能有不同的版本),您可以获得有关字段的所有信息(字段类型,是否需要等)。从本质上讲,GraphQL接受查询 - 这是一种JSON格式的数据 - 并尝试将其解析为先前定义的模式。

您可以发布两种类型的查询:

  • 查询 - 获取多个数据,仅查询查询中定义的那些字段

  • 变异 - 用于创建,更新或删除数据

在项目中使用GraphQL之前,我们应该定义包含所有可能的实体和实体字段的模式,并解决我们定义获取或更新数据的方式和位置。图片标题

获取数据方法概述

实际上,来自客户端页面的大量请求只是从数据库(或其他数据源,如Elasticsearch)获取数据,因此让我们简要地检查一下我们可以用来获取数据的方法,并澄清每种方法可能存在的缺陷。

第一个 - 我说最着名的 - 是使用实体框架(EF)。在我看来,EF有点复杂,特别是如果我们只是谈论从数据库获取数据。此外,如果数据库表先前已更新,我们不应忘记更新项目中定义的模型。

第二种方法基于轻量级ORM NReco.Data,它具有广泛的DB适配器(允许连接到任何流行的数据库 - MSSQL,PostgreSQL,MySQL,Elasticsearch等)。但是,在我们的表更改时,我们仍然遇到更新方案的问题。让我们看一个允许我们在JSON格式的文件中定义所有模式(甚至关系)的组件 - GraphQL.Net API到SQL-db

让我们配置架构并逐步运行.NET Core Web Application的几个查询:

1.首先,让我们在Startup.cs中设置数据库配置字符串和模式定义

public  void  ConfigureServices(IServiceCollection  services){
  服务。AddMvc()。SetCompatibilityVersion(compatibilityVersion进行。Version_2_1);
  服务。AddSingleton < IDbFactory,DbFactory >((servicePrv)=> {
    // db-provider特定的配置代码:
    返回 新 DbFactory(微软。数据。sqlite的。SqliteFactory。实例){
      LastInsertIdSelectText  =  “SELECT last_insert_rowid()”
    };
  });
  服务。AddSingleton < IDbCommandBuilder,DbCommandBuilder >((servicePrv)=> {
    VAR  dbCmdBuilder  =  新 DbCommandBuilder将(servicePrv。GetRequiredService < IDbFactory >());
    dbCmdBuilder。SelectTemplate  =  “SELECT @columns FROM @ table @ where [WHERE {0}] @ orderby [ORDER BY {0}] @recordcount [LIMIT {0}] @recordoffset [OFFSET {0}]” ;
    //在这里初始化数据视图:
    return  dbCmdBuilder ;
  });

  服务。AddScoped < IDbConnection >((servicePrv)=> {
    var  dbFactory  =  servicePrv。GetRequiredService < IDbFactory >();
    var  conn  =  dbFactory。CreateConnection();
    康涅狄格州。ConnectionString  =  String。格式(“Filename = {0}”,路径。组合(ApplicationPath,“../ Data / northwind.db”));
    返回 康涅狄格州 ;
  });

  服务。AddScoped < DbDataAdapter >();
  //通过json-file配置模式
  服务。AddScoped < IGraphqlAdapter >((servicePrv)=> {
    var  dbAdapter  =  servicePrv。GetRequiredService < DbDataAdapter >();
    var  graphqlAdapter  =  new  GraphqlDbAdapter(
      dbAdapter,
      JsonConvert。DeserializeObject < GraphqlConfiguration >(
        系统。IO。档案。ReadAllText(Path。组合(ApplicationPath,“schemaDbDefinition.json”))
      )
    );

    return  graphqlAdapter ;
  });
}

2.第二步是定义“schemaDbDefinition.json”文件,其中我们有下一个属性:

  • 选项 - 它是一个非必要的属性,可能会被省略; 包含过滤器,分页,排序等

    • 默认情况下启用分页,用于在查询中定义排序参数(sortBy,direction)

    • 默认情况下,排序已启用,用于在查询中定义排序参数(sortBy,direction)

    • 默认情况下,过滤器已启用,用于在查询中定义过滤器参数(默认情况下为“过滤器”)

  • SchemaObjects - 基于来自DB的数据表的已定义GraphQL对象的数组

    • Relex - 字符串表达式(阅读更多信息NReco.Relex),其中所有字段值都来自父模式对象,可以在条件中使用。

    • SingleName - GraphQL查询中单个对象的名称

    • ListName - GraphQL查询中对象列表的名称

    • 表 - 数据库表名

    • 描述 - 可选字段; 出现在GraphiQL IDE中幷包含简短描述

    • 字段 - GraphQL查询中可用的所有字段

    • RelatedObjects - 相关对象的数组; 只能由架构中定义的对象使用

最终,它应该是这样的:

{
  “选项”:{
  “分页”:{
  “ArgumentNameForFirst”:“limitItems”
  }
  },
  “SchemaObjects”:[
    {
      “SingleName”:“客户”,
      “ListName”:“客户”,
      “表”:“客户”,
      “描述”:“客户表 - 包含有关客户的数据”,
      “领域”:[
      {
        “姓名”:“id”,
        “专栏”:“客户ID”,
        “DataType”:“string”,
        “描述”:“唯一标识符 - 也用于连接订单”
      },
      {
        “名称”:“公司名称”,
        “DataType”:“string”
      },
      {
        “名称”:“ContactName”,
        “DataType”:“string”
      }
      ]
      “RelatedObjects”:[
        {
        “名称”:“顺序”,//指相关对象的名称
        “Relex”:“订单(CustomerID = \”id \“:var)[*]”  //用于加载相关对象的查询
        },
        {
        “名称”:“订单”,
        “Relex”:“订单(CustomerID = \”id \“:var)[*]”
        }
      ]
    },
    {
      “SingleName”:“订单”,
      “ListName”:“订单”,
      “表”:“订单”,
      “领域”:[
        {
          “名称”:“orderId”,
          “列”:“OrderID”,
          “DataType”:“int32”
        },
        {
          “名称”:“customerId”,
          “专栏”:“客户ID”,
          “DataType”:“string”
        },
        {
          “名称”:“OrderDate”,
          “DataType”:“datetime”
        },
        {
          “名称”:“运费”,
          “DataType”:“十进制”
        }
      ]
    }
  ]
}

3.让我们将一个GraphQL适配器添加到API方法的控制器:

公共 类 GraphQLRequest {
  public  string  OperationName { get ; 设置 ; }
  public  string  Query { get ; 设置 ; }
  public  JObject  Variables { get ; 设置 ; }
}

[ HttpPost ]
public  async  Task < IActionResult >  PostAsync([ FromBody ] GraphQLRequest  queryRequest,CancellationToken  cancellationToken){
  var  graphqlResult  =  await  _graphqlAdapter。ExecuteToJsonAsync(
  新的 GraphQLQuery {
    Query  =  queryRequest。查询,
    OperationName  =  queryRequest。OperationName,
    变量 =  queryRequest。变量。ToInputs()
  },
  的CancellationToken
);

返回 Ok(
graphqlResult
);
}

4.让我们的订单获得所有客户:

图片标题

5.或者使用最后2个订单获取特定客户的数据:

图片标题

6.应用过滤器并获得超过870运费的所有订单:

图片标题

摘要

使用NReco.GraphQL定义模式,数据获取非常简单,只需几步即可完成。您不再需要创建类来定义GraphQL方案并在更新后重建整个解决方案 - 您只需稍微更改JSON文件即可。NReco.GraphQL的另一个好处是这个数据库适配器可以轻松连接到任何流行的数据库。


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