HotChocolate GraphQL - 无法对实体框架中定义的 POCO 的 ExtensionType 应用过滤或排序

问题描述 投票:0回答:1

我无法对由 ObjectTypeExtension 扩展的 EF 实体的导航属性应用 UseFiltering 方法。但是,当我禁用 ObjectTypeExtension 并直接在导航属性上的 EF 生成的类上应用 [UseFiltering()] 属性时,代码可以完美运行。当启用 ObjectExtensionType 时,这一挑战似乎特别明显。根本目标是避免 EF 实体和 HotChocolate 代码交织在一起,从而促使使用 ObjectExtensionType 来增强实体的功能 - 这是利用扩展类型背后的关键原理。

抛线错误:

descriptor.Field(t => t.Brands).UseFiltering();

错误信息:

1. Could not load type 'HotChocolate.Types.IInputType' from assembly 'HotChocolate.Types, Version=13.8.1.0, Culture=neutral, PublicKeyToken=null'. (Product.QL.Types.LobTeamType)

   at HotChocolate.Configuration.TypeInitializer.DiscoverTypes()
   at HotChocolate.Configuration.TypeInitializer.Initialize()
   at HotChocolate.SchemaBuilder.Setup.InitializeTypes(SchemaBuilder builder, IDescriptorContext context, IReadOnlyList`1 types)
   at HotChocolate.SchemaBuilder.Setup.Create(SchemaBuilder builder, LazySchema lazySchema, IDescriptorContext context)
   at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaAsync(ConfigurationContext context, RequestExecutorSetup setup, RequestExecutorOptions executorOptions, IServiceProvider schemaServices, TypeModuleChangeMonitor typeModuleChangeMonitor, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaServicesAsync(ConfigurationContext context, RequestExecutorSetup setup, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorNoLockAsync(String schemaName, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorAsync(String schemaName, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorProxy.GetRequestExecutorAsync(CancellationToken cancellationToken)
   at HotChocolate.AspNetCore.HttpPostMiddlewareBase.HandleRequestAsync(HttpContext context)
   at HotChocolate.AspNetCore.HttpPostMiddlewareBase.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.<>c__DisplayClass19_0.<<UseCancellation>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
//EF Entity    
public partial class LobTeam
    {
      public int LobTeamId { get; set; }
      public Guid LobTeamUid { get; set; }
      public string Name { get; set; } = null!;
      public int StatusId { get; set; }
      public virtual ICollection<LobTeamBrand> LobTeamBrands { get; set; } = new List<LobTeamBrand>();
      public virtual ICollection<Platform> Platforms { get; set; } = new List<Platform>();
      public virtual ICollection<Brand> Brands { get; set; }
     }

//ObjectTypeExtension class
    public sealed class LobTeamType : ObjectTypeExtension<LobTeam>
    {
        protected override void Configure(IObjectTypeDescriptor<LobTeam> descriptor)
        {
            descriptor
                .Field(t => t.LobTeamBrands)
                .Ignore();

            descriptor
                .Field(t => t.Brands)
                .UseFiltering();
        }
    }


//Program.cs file
builder.Services
    .AddGraphQLServer()
    .AddQueryType<ProductQuery>()
    .RegisterDbContext<ProductDataContext>(DbContextKind.Resolver)
    .AddProjections()
    .AddFiltering()
    .AddSorting()
    .AddTypeExtension<LobTeamType>();
filtering hotchocolate type-extension
1个回答
0
投票

显然不能在基本 EF 实体上使用 UseFiltering()。相反,HotChocolate 希望该字段属于 HotChocolate 对象扩展类型。因此,在上面的示例中,创建一个 BrandType objectExtension 并使用 BrandType 在 LobTeamType 上应用 UseFiltering()。 为了将其提升到一个新的水平,我创建了一个通用拦截器,它将创建对象扩展类型并在运行时应用 UseFiltering(),而不是为每种类型创建单独的类型。这帮助我对 ICollection 类型的所有导航属性应用过滤。这是它的代码。

public class FilterCollectionTypeInterceptor : TypeInterceptor
{
    private static readonly List<string> _mappedTypes = new();

    private static bool IsCollectionType(Type t)
        => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>);

    public override void OnBeforeRegisterDependencies(ITypeDiscoveryContext discoveryContext, DefinitionBase? definition)
    {
        if (definition is not ObjectTypeDefinition objectTypeDefinition) return;

        if (objectTypeDefinition.RuntimeType.Name != "Object") return;

        var keyBuilder = new StringBuilder();

        for (var i = 0; i < objectTypeDefinition.Fields.Count; i++)
        {
            var field = objectTypeDefinition.Fields[i];
            if (field.ResultType is null || !IsCollectionType(field.ResultType)) 
                continue;

            keyBuilder.Clear(); // Clear StringBuilder for the next key
            keyBuilder.Append(objectTypeDefinition.Name.ToLower()).Append('.').Append(field.Name.ToLower());
            var key = keyBuilder.ToString();

            if (_mappedTypes.Contains(key)) 
                continue;

            var descriptor = field.ToDescriptor(discoveryContext.DescriptorContext);
            descriptor.UseFiltering(typeof(FilterInputType<>).MakeGenericType(field.ResultType.GenericTypeArguments[0]));
            objectTypeDefinition.Fields[i] = descriptor.ToDefinition();
            
            _mappedTypes.Add(key);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.