在具有多个表的Linq查询中使用递归层次结构树结构并返回一些Json值

时间:2015-03-26 13:55:18

标签: c# json linq recursion

我有一个复杂的层次结构,我使用了RecursiveJoin Extension方法,它返回给我一个父节点,子节点和深度的树结构。所以没关系,但我需要从ScoreItem表中计算总得分点数据库。我在下面的t-sql中编写了这个简单的计算方法,

Begin
    Select 
        sp.Name,
        u.FirstName + ' ' + u.LastName as NameAndSurname, 
        rgc.Name as ScoreCard,
        si.TotalPoint 
    from Score s
        inner join ScoreItem si on si.ScoreId = s.Id
        inner join ProjectResearchGroup prg on si.ProjectResearchGroupId = prg.Id
        inner join RgClone rgc on prg.RgCloneId = rgc.Id
        inner join Salespoint sp on s.SalesPointId = sp.Id
        inner join SalesHierarchySalesPoint shsp on sp.Id = shsp.SalesPointId
        inner join SalesHierarchy sh on shsp.SalesHierarchyId = sh.Id
        inner join [User] u on u.Id = sh.CompanyResponsibleId
    where sh.Id in 
        (Select Id 
        from SalesHierarchy 
        where ParentId in 
            (Select Id 
            from SalesHierarchy 
            where ParentId in 
                (Select Id 
                from SalesHierarchy 
                where ParentId in 
                    (Select Id 
                    from SalesHierarchy 
                    where CompanyId = 2 
                        and ParentId is null))))
        and si.IsValidForSalesPoint = 1 
End 

这也是我的后端代码,用于尝试从上面的t-sql查询实现linq查询。

IEnumerable<FlatData> _SalesHierarchy = db.SalesHierarchy
                                         .Select(sh =>
                                         new FlatData()
                                         {
                                         Id = sh.Id,
                                         ParentId = sh.ParentId ?? 0,
                                         Text = sh.Name
                                         })
                                        .ToList();

IEnumerable<DeepNodeData> nodes = _SalesHierarchy.RecursiveJoin(e => e.Id, e => e.ParentId,
(FlatData sh, int index, int depth, IEnumerable<DeepNodeData> children) =>
  {
    return new DeepNodeData
        {
          Id = sh.Id,
          ParentId = sh.ParentId,
          Text = sh.Text,
          Children = children,
          Depth = depth
        };

因此,上述代码会返回this result

所以我想为我的web api返回Json输出,例如这些

"data": [
        {
            "level1": "XXXX,XXXX,XXXX",
            "level2": "XXXX,XXXX,XXX",
            "level3": "XXXX,XXXX,XX",
            "level4": "XXXX,XXXX,X",
            "val": 2
        },
    ]
}; 

如何使用其他linq查询实现层次结构查询并返回Json格式以上。如果您对此有任何建议和样品申请,请与我分享,

1 个答案:

答案 0 :(得分:1)

RecursiveJoin Extension看起来很不错,但我认为您无需使用该代码的全部功能来实现您的目标。如果我正确理解您的问题,您需要枚举从根到叶的所有节点列表,将每个列表转储到JSON对象中。为此,首先创建以下扩展方法:

public static class RecursiveExtensions
{
    public static IEnumerable<TValue> SelfAndParents<TKey, TValue>(this TValue value, IDictionary<TKey, TValue> dictionary, Func<TValue, TKey> getParentKey)
    {
        HashSet<TValue> returned = new HashSet<TValue>();
        do
        {
            yield return value;
            if (!dictionary.TryGetValue(getParentKey(value), out value))
                yield break;
            if (returned.Contains(value))
                throw new InvalidOperationException("Circular reference");
            returned.Add(value);
        }
        while (true);
    }

    public static IEnumerable<List<TValue>> FlattenTree<TKey, TValue>(this IEnumerable<TValue> nodes, Func<TValue, TKey> getKey, Func<TValue, TKey> getParentKey)
    {
        var list = nodes.ToList();                                                          // Don't iterate through the node list more than once.
        var parentKeys = new HashSet<TKey>(list.Select(getParentKey));                      // Built a set of parent keys.
        var dict = list.ToDictionary(getKey);                                               // Build a dictionary of key to value
        var results = list
            .Where(node => !parentKeys.Contains(getKey(node)))                              // Filter out non-leaf nodes
            .Select(node => node.SelfAndParents(dict, getParentKey).Reverse().ToList());    // For each leaf return a list going from root to leaf.
        return results;
    }
}

然后按如下方式使用它们:

public static class TestFlatten
{
    public static IEnumerable<FlatData> GetFlatData()
    {
        // Get sample data for testing purposes.
        var list = new List<FlatData>
        {
            new FlatData { Id = 1, ParentId = 0, Text = "Some Root Node" },
            new FlatData { Id = 2, ParentId = 0, Text = "Anadolu Satış Merkezi" },
            new FlatData { Id = 3, ParentId = 2, Text = "Emrullah Çelik" },
            new FlatData { Id = 4, ParentId = 3, Text = "Ahmet İşler" },
            new FlatData { Id = 5, ParentId = 4, Text = "Elpa Pazarlama Nazmi Appak" },
            new FlatData { Id = 6, ParentId = 4, Text = "Elpa Pazarlama Nazmi Appak Redux" },
            new FlatData { Id = 11, ParentId = 1, Text = "Some Child of Some Root Node" },
        };
        return list;
    }

    public static void Test()
    {
        var nodes = GetFlatData();
        var flatNodes = nodes.FlattenTree(d => d.Id, d => d.ParentId);
        var results = flatNodes.Select(
            list => list
                .Select((d, i) => new KeyValuePair<int, FlatData>(i, d))
                .ToDictionary(pair => string.Format("level{0}", pair.Key + 1), pair => pair.Value.Text))
            .ToList();
        var json = JsonConvert.SerializeObject(new { data = results }, Formatting.Indented);
        Debug.WriteLine(json);
    }
}

这会产生JSON输出:

{
  "data": [
    {
      "level1": "Anadolu Satış Merkezi",
      "level2": "Emrullah Çelik",
      "level3": "Ahmet İşler",
      "level4": "Elpa Pazarlama Nazmi Appak"
    },
    {
      "level1": "Anadolu Satış Merkezi",
      "level2": "Emrullah Çelik",
      "level3": "Ahmet İşler",
      "level4": "Elpa Pazarlama Nazmi Appak Redux"
    },
    {
      "level1": "Some Root Node",
      "level2": "Some Child of Some Root Node"
    }
  ]
}
这是你想要的吗?在这里,我利用了Json.NET将字典序列化为JSON对象的事实,以动态创建“levelI”属性作为字典键。此外,由于您没有定义"val"值,因此我没有将其包含在字典中。