GraphQL:从作用域引用的类型变量,但未定义

时间:2019-11-18 20:51:33

标签: c# .net-core graphql

我正在尝试通过Expression检索属性的值。但是,当我运行代码时,出现异常

  

未处理的异常。 System.InvalidOperationException:从作用域“”引用的类型为“ GraphQlMcve.Program + Teacher”的变量“ teacher”,但未定义

当我尝试编译表达式时,会在下面的方法中发生这种情况。

protected FieldBuilder<T, object> PupilListField(string name,
    Expression<Func<T, IReadOnlyCollection<Pupil>>> pupils)
{
    return BaseAugmentedPupilListQuery(name)
        .Resolve(context =>
        {
            IEnumerable<Pupil> pupilList =
                Expression.Lambda<Func<IReadOnlyCollection<Pupil>>>(pupils.Body).Compile()();
            return AugmentedPupilListQueryBaseResolver(context, pupilList);
        });
}

我使用的表达式是teacher => teacher.Pupils。为什么会这样?

下面是一个可运行的示例。


下面的代码示例使用GraphQL NuGet package Install-Package GraphQL -Version 2.4.0

using GraphQL.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using GraphQL;
using GraphQL.Types;

namespace GraphQlMcve
{
    internal class Program
    {
        private static void Main()
        {
            const string query = @"{ teachers { id, name, pupils(id: ""2"") { id, name } } }";
            Schema schema = new Schema { Query = new SchoolQuery() };
            Console.WriteLine(schema.Execute(_ => { _.Query = query; _.ExposeExceptions = true; _.ThrowOnUnhandledException = true; }));
        }

        private class Pupil
        {
            public string Id { get; set; }
            public string Name { get; set; }
        }

        private class PupilType : ObjectGraphType
        {
            public PupilType()
            {
                Field<NonNullGraphType<IdGraphType>>(nameof(Pupil.Id));
                Field<StringGraphType>(nameof(Pupil.Name));
            }
        }

        private class Teacher
        {
            public string Id { get; set; }
            public string Name { get; set; }
            public List<Pupil> Pupils { get; set; }
        }

        private class TeacherType : BaseEntityGraphType<Teacher>
        {
            public TeacherType()
            {
                Field<NonNullGraphType<IdGraphType>>(nameof(Teacher.Id));
                Field<StringGraphType>(nameof(Teacher.Name));
                PupilListField(nameof(Teacher.Pupils), teacher => teacher.Pupils);
            }
        }

        private class SchoolQuery : BaseEntityGraphType
        {
            public SchoolQuery()
            {
                List<Pupil> pupils = new List<Pupil>
                {
                    new Pupil { Id = "1", Name = "Sarah" },
                    new Pupil { Id = "2", Name = "Adam" },
                    new Pupil { Id = "3", Name = "Gill" },
                };

                List<Teacher> teachers = new List<Teacher> { new Teacher { Id = "4", Name = "Sarah", Pupils = pupils} };

                PupilListField("pupils", pupils);

                Field<ListGraphType<TeacherType>>(
                    "teachers",
                    arguments: new QueryArguments(
                        new QueryArgument<IdGraphType> { Name = "id" }
                    ),
                    resolve: context => teachers
                );
            }
        }

        private abstract class BaseEntityGraphType<T> : ObjectGraphType<T>
        {
            protected FieldBuilder<T, object> PupilListField(string name,
                Expression<Func<T, IReadOnlyCollection<Pupil>>> pupils)
            {
                return BaseAugmentedPupilListQuery(name)
                    .Resolve(context =>
                    {
                        IEnumerable<Pupil> pupilList =
                            Expression.Lambda<Func<IReadOnlyCollection<Pupil>>>(pupils.Body).Compile()();
                        return AugmentedPupilListQueryBaseResolver(context, pupilList);
                    });
            }

            protected FieldBuilder<T, object> PupilListField(string name, IReadOnlyCollection<Pupil> pupils)
            {
                return BaseAugmentedPupilListQuery(name)
                    .Resolve(context => AugmentedPupilListQueryBaseResolver(context, pupils));
            }

            private FieldBuilder<T, object> BaseAugmentedPupilListQuery(string name)
            {
                return Field<ListGraphType<PupilType>>()
                    .Name(name)
                    .Description("")
                    .Argument<IdGraphType>("id", "");
            }

            private static IEnumerable<Pupil> AugmentedPupilListQueryBaseResolver(
                ResolveFieldContext<T> context,
                IEnumerable<Pupil> pupils)
            {
                string id = context.GetArgument<string>("id");
                return string.IsNullOrWhiteSpace(id) ? pupils : pupils.Where(pupil => pupil.Id == id);
            }
        }

        private abstract class BaseEntityGraphType : BaseEntityGraphType<object> { }
    }
}

1 个答案:

答案 0 :(得分:1)

IEnumerable<Pupil> pupilList = Expression.Lambda<Func<IReadOnlyCollection<Pupil>>>(pupils.Body).Compile()();

这部分代码是错误的。您选择表达式的一部分并进行编译。您编译的部分具有教师表达,并且您破坏了与之的联系。您可以做的是:编译已经在函数中传递的主表达式。

var pupilList = puplis.Compile()(/* you need to pass here an actual object */); 

编译表达式时,将创建一个处理对象的函数,但您没有传递该对象。在您的教师示例中,它必须是教师对象。