【问题标题】:GraphQL: Variable of type referenced from scope, but it is not definedGraphQL:从范围引用的类型变量,但未定义
【发布时间】:2019-11-18 20:51:33
【问题描述】:

我正在尝试通过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 =&gt; 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> { }
    }
}

【问题讨论】:

    标签: c# .net-core graphql


    【解决方案1】:
    IEnumerable<Pupil> pupilList = Expression.Lambda<Func<IReadOnlyCollection<Pupil>>>(pupils.Body).Compile()();
    

    这部分代码是错误的。您选择表达式的一部分并对其进行编译。你编译的部分有一个老师的表达,你打破了与它的关系。你可以做的是:编译你已经在你的函数中传递的主表达式。

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

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

    【讨论】:

    • 感谢您的帮助。我过于复杂了,并且能够使用pupils.Compile()(context.Source)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 2015-10-08
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多