【问题标题】:Creating GraphQL Structure from Dot Notation String in c#在 c# 中从点符号字符串创建 GraphQL 结构
【发布时间】:2019-11-18 15:30:39
【问题描述】:

以下 javascript 问题与我尝试解决的问题相同,但在 c# 中

How can I merge 2 dot notation strings to a GraphQL query string

预期的结构是

{
    "Case": {
        "Owner": {
            "Name": null,
            "ProfilePic": null
        },
        "CaseNo": null,
        "FieldOfLaw":{
            "Name": null
        },
        "CaseType": {
            "Name": null
        },
        "CaseSubType": {
            "Name": null
        },
    },
    "Client":{
        "Policy":{
            "PolicyNo": null
        }
    }
}

我目前的输出是

{
    "Case": {
        "Owner": {
            "Name": null,
            "ProfilePic": null
        },
        "CaseNo": null,
        "FieldOfLaw": null,
        "CaseType": null,
        "CaseSubType": null
    }
}

下面是我尝试使用 ExpandoObjects 来尝试动态生成所需的对象。任何正确方向的建议或指示将不胜感激。

public static void Main(string[] args)
{
    var FieldList = new List<string>
    {
    "Case.Owner.Name",
    "Case.Owner.ProfilePic",
    "Case.CaseNo",
    "Case.FieldOfLaw.Name",
    "Case.CaseType.Name",
    "Case.CaseSubType.Name",
    "Client.Policy.PolicyNo",
    };

    Parser graphQL = new Parser();
    var result = graphQL.Parse(FieldList);
    Console.Write(result);
}

下面是实际的 parse 方法,所以我在每个元素上运行一个聚合函数来创建并返回 expando 对象到初始持有者。我递归遍历每个拆分字符串,一旦拆分列表中没有剩余项目,我就退出递归。

public class Parser
    {
        public string Parse(List<string> fieldList)
        {
            // List<ExpandoObject> queryHolder = new List<ExpandoObject>();
            ExpandoObject intialSeed = new ExpandoObject();

            fieldList.Aggregate(intialSeed, (holder, field) =>
            {
                holder = ParseToObject(holder, field.Split('.').ToList());
                return holder;
            });

            return JsonConvert.SerializeObject(intialSeed);
        }

        public ExpandoObject ParseToObject(ExpandoObject holder, List<string> fieldSplit, string previousKey = null)
        {
            if (fieldSplit.Any())
            {
                var item = fieldSplit.Shift();

                if (item == null)
                    return holder;

                // If the current item doesn't exists in the dictionary
                if (!((IDictionary<string, object>)holder).ContainsKey(item))
                {
                    if (((IDictionary<string, object>)holder).Keys.Count() == 0)
                        holder.TryAdd(item, null);
                    else
                        _ = ((IDictionary<string, object>)holder).GetItemByKeyRecursively(previousKey, item);
                }

                previousKey = item;

                ParseToObject(holder, fieldSplit, previousKey);
            }

            return holder;
        }

    }

这是我的两个扩展方法,当 GetItemByKeyRecursively 在它的递归中进入第三级时,我遇到了问题,例如。

我正在添加 FieldOfLaw,它将属性添加到 Case expandoObject 但不知道如何返回包含 Owner、CaseNo 等的叶子。

 public static class CollectionExtensions
    {
        public static T Shift<T>(this IList<T> list)
        {
            var shiftedElement = list.FirstOrDefault();
            list.RemoveAt(0);
            return shiftedElement;
        }

        public static IDictionary<string, object> GetItemByKeyRecursively(this IDictionary<string, object> dictionary, string parentKey, string keyToCreate)
        {
            foreach (string key in dictionary.Keys)
            {
                var leaf = dictionary[key];

                if (key == parentKey)
                {
                    var @value = dictionary[key];
                    if (@value is ExpandoObject)
                    {
                        (@value as ExpandoObject).TryAdd(keyToCreate, null);
                    }
                    else if (@value == null)
                    {
                        var item = new ExpandoObject();
                        item.TryAdd(keyToCreate, null);
                        dictionary[key] = item;
                    }
                    return dictionary;
                }

                if (leaf == null)
                    continue;

                return GetItemByKeyRecursively((IDictionary<string, object>)leaf, parentKey, keyToCreate);
            }

            return null;
        }
    }

【问题讨论】:

    标签: c# algorithm graphql


    【解决方案1】:

    没有什么是你不能通过声明方式完成的。

    public string Parse(List<string> fieldList)
    {
        var fieldPaths = fieldList.Select(x => x.Split('.').ToList());
        var groups = fieldPaths.GroupBy(x => x.First(), x => x.Skip(1));
        return ParseGroups(groups, 1);
    }
    
    private string ParseGroups(IEnumerable<IGrouping<string, IEnumerable<string>>> groups, int level)
    {
        string indent = new string('\t', level - 1);
    
        var groupResults = groups.Select(g =>
            !g.First().Any() ? 
                $"\t{indent}{g.Key}: null" :
                $"\t{indent}{g.Key}: " + string.Join(", \n",
                     ParseGroups(g.GroupBy(x => x.First(), x => x.Skip(1)), level + 1))
        );
    
        return indent + "{\n" + string.Join(", \n", groupResults) + "\n" + indent + "}";
    }
    

    在此处查看完整的示例代码:https://dotnetfiddle.net/RLygjt

    【讨论】:

    • 这是解决这个问题的一种非常酷的方法,我今天确实用上面的一些类似代码解决了这个问题。稍后如果有人感兴趣,会尝试发布。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 2013-10-08
    • 1970-01-01
    • 2016-02-12
    相关资源
    最近更新 更多