如果在GraphQL中未选择任何字段,则阻止联接表

时间:2018-10-30 09:22:05

标签: c# graphql asp.net-core-2.0

我是 GraphQL 的新手。

当前,我有一个查询定义,用于搜索学生及其参加的

var studentsQueryArguments = new QueryArguments();
            studentsQueryArguments.Add(new QueryArgument<ListGraphType<IntGraphType>> { Name = "ids", Description = "Student indexes." });
            studentsQueryArguments.Add(new QueryArgument<RangeModelType<double?, double?>> {Name = "age", Description = "Age range of student."});
            Field<ListGraphType<StudentType>>(
                "students",
                arguments: studentsQueryArguments,
                resolve: context =>
                {
                    var students = relationalDbContext.Students.AsQueryable();
                    var classes = relationalDbContext.Classes.AsQueryable();
                    var participatedClasses = relationalDbContext.StudentInClasses.AsQueryable();

                    var ids = context.GetArgument<List<int>>("ids");
                    var age = context.GetArgument<RangeModel<double?, double?>>("age");

                    if (ids != null)
                        students = students.Where(x => ids.Contains(x.Id));

                    if (age != null)
                    {
                        var from = age.From;
                        var to = age.To;

                        if (from != null)
                            students = students.Where(x => x.Age >= from);

                        if (to != null)
                            students = students.Where(x => x.Age <= to);
                    }

                    var results = (from student in students
                        select new StudentViewModel
                        {
                            Id = student.Id,
                            Age = student.Age,
                            FullName = student.FullName,
                            Photo = student.Photo,
                            Classes = from participatedClass in participatedClasses
                                from oClass in classes
                                where participatedClass.StudentId == student.Id &&
                                      participatedClass.ClassId == oClass.Id
                                select new ClassViewModel
                                {
                                    Id = oClass.Id,
                                    ClosingHour = oClass.ClosingHour,
                                    Name = oClass.Name,
                                    OpeningHour = oClass.OpeningHour
                                }
                        });

                    return results;
                });

在上面的代码中,我加入了学生班级。 使用查询

{
  students(ids: [1, 2, 3]) {
    id
    age
    classes {
      name
      openingHour
      closingHour
    }
  }
}
返回

学生及其。没关系。

我想要的是当我使用此查询时:

{
  students(ids: [1, 2, 3]) {
    id
    age
  }
}

我的应用程序不会加入学生班级,而只返回学生信息。

有可能吗?

谢谢

1 个答案:

答案 0 :(得分:0)

我做了一个超酷的扩展方法,该方法返回所选内容是否包含在GraphQL查询中。 如果选择中存在导航属性,则将其包含在查询中。


扩展方法

using System;
using System.Linq;
using GraphQL.Language.AST;
using GraphQL.Types;    

public static class ContextExtensions
{
    /// <summary>
    /// Returns true if the given fieldSelector exists in the selection of the query.
    /// </summary>
    /// <param name="context">The working context</param>
    /// <param name="fieldSelector">The query of the field selector. For example items:organizationUnits:displayName</param>
    /// <param name="namespaceSeperator">The seperator character of the fieldSelector. Default is :</param>
    /// <returns></returns>
    public static bool HasSelectionField(this ResolveFieldContext<object> context, string fieldSelector, char namespaceSeperator = ':')
    {
        if (string.IsNullOrWhiteSpace(fieldSelector))
        {
            return false;
        }

        if (context.SubFields == null)
        {
            return false;
        }

        var fragments = fieldSelector.Split(new[] { namespaceSeperator }, StringSplitOptions.RemoveEmptyEntries);

        if (fragments.Length == 1)
        {
            return context.SubFields.ContainsKey(fragments[0]);
        }

        if (context.SubFields[fragments[0]] == null)
        {
            return false;
        }

        if (context.SubFields[fragments[0]].SelectionSet == null)
        {
            return false;
        }

        if (context.SubFields[fragments[0]].SelectionSet.Selections == null)
        {
            return false;
        }


        var selections = context.SubFields[fragments[0]].SelectionSet.Selections;

        for (var i = 1; i < fragments.Length; i++)
        {
            if (selections == null)
            {
                return false;
            }

            var field = selections.Select(selection => (Field)selection).FirstOrDefault(f => f.Name == fragments[i]);
            if (field == null)
            {
                return false;
            }

            if (i == fragments.Length - 1)
            {
                return true;
            }

            selections = field.SelectionSet?.Selections;
        }

        return true;
    }
}

用法

protected override async Task<PagedResultDto<UserDto>> Resolve(ResolveFieldContext<object> context)
{
    var total_count_exists = context.HasSelectionField("totalCount"); //true
    var items_name_exists = context.HasSelectionField("items:name"); //true
    var items_roles_name_exists = context.HasSelectionField("items:roles:name"); //true
    var items_organizationUnits_displayName_exists = context.HasSelectionField("items:organizationUnits:displayName"); //true
    var items_organizationUnits_xyz_exists = context.HasSelectionField("items:organizationUnits:xyz"); //false
}

样本查询

query MyQuery {
  users(id: 1) {
    totalCount
    items {
      name
      surname

      roles {
        id
        name
        displayName
      }

      organizationUnits {
        id
        code
        displayName
      }
    }
  }
}