c# - 如何处理表示 sql 关系的 graphql listgraphtypes
问题描述
我面临的问题不是很典型,因为我试图以某种方式制作通用的 graphql web api。我根据我在互联网上找到的一些文章解决了我的问题,这些文章我根据自己的需要进行了重构。问题是我正在基于数据库元数据制作一个 graphql api,我已经设法创建了一个根查询,尽管现在的问题在于类型。工作流本质上是循环遍历包含表名和列的集合,将它们添加到类型/字段。然而问题是,当我想说查询子列表时,我没有来自其他类型的子字段。
在本质上:
query getCategoriesAndRelatedProducts {
categories {
categoryId
productList {
//productList got no fields
}
}
}
我没有像这样从模型到 GraphType 进行法线映射
public class ProductObject : ObjectGraphType<Product>
{
private readonly IProductService product;
public ProductObject(IProductService p)
{
product = p;
Field(f => f.Id);
Field(f => f.Name);
FieldAsync<ProductTypeObject>("type",
resolve: async context => await product.GetProductType(context.Source.Id));
}
}
我的根查询是以这种方式完成的
public class NorthWindQuery : ObjectGraphType<object>
{
private readonly NorthWindContext _dbContext;
private IDatabaseMetadata _dbMetadata;
private ITableNameLookup _tableNameLookup;
public NorthWindQuery(NorthWindContext dbContext, IDatabaseMetadata dbMetadata,
ITableNameLookup tableNameLookup)
{
_dbMetadata = dbMetadata;
_tableNameLookup = tableNameLookup;
_dbContext = dbContext;
foreach (var metaTable in _dbMetadata.GetTableMetadatas())
{
var tableType = new TableType(metaTable);
var friendlyTableName = _tableNameLookup.GetFriendlyName(metaTable.TableName);
AddField(new FieldType
{
Name = friendlyTableName,
Type = tableType.GetType(),
ResolvedType = tableType,
Resolver = new MyFieldResolver(metaTable, _dbContext),
Arguments = new QueryArguments(
tableType.TableArgs
)
});
// lets add key to get list of current table
var listType = new ListGraphType(tableType);
AddField(new FieldType
{
Name = $"{friendlyTableName}_list",
Type = listType.GetType(),
ResolvedType = listType,
Resolver = new MyFieldResolver(metaTable, _dbContext),
Arguments = new QueryArguments(
tableType.TableArgs
)
});
}
TableType 是这样完成的:
public class TableType : ObjectGraphType<object>
{
public TableType (TableMetadata tableMetadata)
{
Name = tableMetadata.TableName;
foreach (var tableColumn in tableMetadata.Columns)
{
InitGraphTableColumn(tableColumn);
}
TableArgs.Add(new QueryArgument<IdGraphType> { Name = "id" });
TableArgs.Add(new QueryArgument<IntGraphType> { Name = "first" });
TableArgs.Add(new QueryArgument<IntGraphType> { Name = "offset" });
TableArgs.Add(new QueryArgument<StringGraphType> { Name = "includes" });
}
public QueryArguments TableArgs
{
get; set;
}
private IDictionary<string, Type> _databaseTypeToSystemType;
protected IDictionary<string, Type> DatabaseTypeToSystemType
{
get
{
if (_databaseTypeToSystemType == null)
{
_databaseTypeToSystemType = new Dictionary<string, Type>
{
{ "uniqueidentifier", typeof(String) },
{ "char", typeof(String) },
{ "nvarchar", typeof(String) },
{ "int", typeof(int) },
{ "decimal", typeof(decimal) },
{ "bit", typeof(bool) }
};
}
return _databaseTypeToSystemType;
}
}
private void InitGraphTableColumn(ColumnMetadata columnMetadata)
{
var graphQLType = ResolveColumnMetaType(columnMetadata.DataType).GetGraphTypeFromType(true);
var columnField = Field(
graphQLType,
columnMetadata.ColumnName
);
columnField.Resolver = new NameFieldResolver();
FillArgs(columnMetadata.ColumnName);
}
private void FillArgs(string columnName)
{
if(TableArgs == null)
{
TableArgs = new QueryArguments(
new QueryArgument<StringGraphType>()
{
Name = columnName
});
}
else
{
TableArgs.Add(new QueryArgument<StringGraphType> { Name = columnName });
}
}
private Type ResolveColumnMetaType(string dbType)
{
if (DatabaseTypeToSystemType.ContainsKey(dbType))
return DatabaseTypeToSystemType[dbType];
return typeof(String);
}
基于我只有 1 个 tableType 和 2 个解析器,tableType 是构造类型的类,a 和 2 个解析器用于将 graphql 转换为查询并返回 NameFieldResolver 的值,并且 MyFieldResolver 就像访问形式。
如果有人做过类似的事情,欢迎提供任何帮助。我这样做是因为我有大量模型,并且从模型编写直接映射不是一种选择,因为我必须编写超过 10,000 个方法来运行 api。
解决方案
因此,经过一段时间的思考和调试,我想到我错过了我的方法中的关键一步。我没有将关系视为 GraphType,所以我所做的一切基本上都没有用。所以理论上让我们想象一下最简单的情况:
type Character {
name: String!
appearsIn: [Episode]!
}
Character 是 ObjectGraphType,但 appearsIn 是 Type Episode ObjectGraphType 的 ListGraphType(根据类型也可以是 ObjectGraphType)。因此,appearIn 具有所有在 Episode Type 中也可以找到的字段。
这把我带到了这里,我会做一些伪假设,如果有人读到这篇文章,就可以在 TableType 中了解下一步该做什么:
public class TableType : ObjectGraphType<object>
{
public TableType (TableMetadata tableMetadata)
{
Name = tableMetadata.TableName;
foreach (var tableColumn in tableMetadata.Columns)
{
InitGraphTableColumn(tableColumn);
}
TableArgs.Add(new QueryArgument<IdGraphType> { Name = "id" });
TableArgs.Add(new QueryArgument<IntGraphType> { Name = "first" });
TableArgs.Add(new QueryArgument<IntGraphType> { Name = "offset" });
TableArgs.Add(new QueryArgument<StringGraphType> { Name = "includes" });
}
public QueryArguments TableArgs
{
get; set;
}
private IDictionary<string, Type> _databaseTypeToSystemType;
protected IDictionary<string, Type> DatabaseTypeToSystemType
{
get
{
if (_databaseTypeToSystemType == null)
{
_databaseTypeToSystemType = new Dictionary<string, Type>
{
{ "uniqueidentifier", typeof(String) },
{ "char", typeof(String) },
{ "nvarchar", typeof(String) },
{ "int", typeof(int) },
{ "decimal", typeof(decimal) },
{ "bit", typeof(bool) }
};
}
return _databaseTypeToSystemType;
}
}
private void InitGraphTableColumn(ColumnMetadata columnMetadata)
{
//here check with a if statement is the column.field a object
// if it is a object make a new fieldtype based on that object
// pass a resolver to the field
var graphQLType = ResolveColumnMetaType(columnMetadata.DataType).GetGraphTypeFromType(true);
var columnField = Field(
graphQLType,
columnMetadata.ColumnName
);
columnField.Resolver = new NameFieldResolver();
FillArgs(columnMetadata.ColumnName);
}
private void FillArgs(string columnName)
{
if(TableArgs == null)
{
TableArgs = new QueryArguments(
new QueryArgument<StringGraphType>()
{
Name = columnName
});
}
else
{
TableArgs.Add(new QueryArgument<StringGraphType> { Name = columnName });
}
}
private Type ResolveColumnMetaType(string dbType)
{
if (DatabaseTypeToSystemType.ContainsKey(dbType))
return DatabaseTypeToSystemType[dbType];
return typeof(String);
}
所以本质上一个图可以有一个名称、字段和一个解析器,但是字段可以是另一种类型,在创建一个类型时,我们可以简单地调用一个来自另一种类型的字段的创建,我们有我们的关系是来自我们需要的类型的子关系,并且可以访问该类型的字段。
private void InitGraphTableColumn(ColumnMetadata columnMetadata)
{
//here check with a if statement is the column.field a object
// if it is a object make a new fieldtype based on that object
// pass a resolver to the field
var graphQLType = ResolveColumnMetaType(columnMetadata.DataType).GetGraphTypeFromType(true);
这是至关重要的部分。
推荐阅读
- keyboard - 是否可以使用 FreePascal 测试是否按下了特定键?
- elasticsearch - ElasticSearch 查询在数组字段中查找大于特定长度的值
- python - Python:如何在对数空间中的两条曲线之间绘制等距曲线?
- ruby-on-rails - Docker Compose 和 Rails: Bundler::GemNotFound 在启动时。bundler 是不是在寻找正确的宝石?
- ios - 使用哪些访问级别使枚举仅可用于该项目
- android - 将值传递到另一个页面以打开 PDF
- java - The method addFilter(SerializablePredicate) in the type InMemoryDataProvider is not applicable for the arguments (( desc) -> {})
- python - 如何从 tkinter 的子窗口修改根窗口?
- angular - Angular 8 路由 + 导航:锁定组件
- google-analytics - 如何暗示 Google Analytics API 并在 asp.net mvc core 3.1 中显示它们