使用C#将datatable转换为分层数据结构(JSON)

5
我正在将SQL查询执行到datatable中。查询可以返回多个列。结果以键值格式呈现,表示分层数据。请参见下面的截图。

enter image description here

这张图片展示了三个部分。首先是数据,然后是数据的分层表示和JSON等效表示。
目前,该图显示了四个数据级别,但我们可以有六到七个数据级别。格式将保持不变,但列数可能会改变。
我如何使用C#获得所需结果?我知道这是基本编程,但我很难做到。

你能再详细解释一下吗?你需要从SQL中获取数据并将其转换为JSON格式吗?还是你正在读取JSON并想将其存储在C#对象(数据结构)中?你所描述的数据看起来像是树形数据结构。快速搜索表明,这些默认情况下C#中不可用,但它们是一个简单的结构可以构建。另请参考将JSON反序列化为C#动态对象 - Ian
@Ian。我需要从SQL服务器读取数据,并将这些数据传递给使用AngularJS开发的前端应用程序。因此,我需要将数据转换为树形结构。我不能只将数据转换为JSON,首先我需要将数据转换为所需的格式。 - OpenStack
那么你是用什么来从数据库中读取数据的? - Jack A.
假设您正在使用类似于Entity Framework或LINQ-to-SQL的东西,您可能希望使用GroupBy的LINQ:https://msdn.microsoft.com/en-us/library/bb545971.aspx - Jack A.
@JackA。我实际上正在使用DAX查询,并在SQL表格数据库上执行它。 - OpenStack
显示剩余2条评论
1个回答

6

在您的示例中,使用像您展示的固定级别层次结构,您可以使用 具有分组的LINQ查询 为JSON生成树形结构。以下是一个三级层次结构的示例:

static void Main(string[] args)
{
    var data = new List<Data>
    {
        new Data("Food", "1_g", "beverage", "2_b", "hot", "3_h"),
        new Data("Food", "1_g", "beverage", "2_b", "cold", "3_c"),
        new Data("Food", "1_g", "fruit", "2_f", "juicy", "3_j"),
        new Data("Food", "1_g", "fruit", "2_f", "solid", "3_s"),
        new Data("Food", "1_g", "cookie", "2_c", "chocolate", "3_cho"),
    };

    var tree = from l1 in data
                group l1 by new { key = l1.Key_L1, name = l1.L1 } into group1
                select new
                {
                    key = group1.Key.key,
                    name = group1.Key.name,
                    children = from l2 in group1
                                group l2 by new { key = l2.Key_L2, name = l2.L2 } into group2
                                select new
                                {
                                    key = group2.Key.key,
                                    name = group2.Key.name,
                                    children = from l3 in group2
                                                select new { key = l3.Key_L3, name = l3.L3 }
                                }
                };

    var serializer = new JavaScriptSerializer();
    Console.WriteLine(serializer.Serialize(tree));
    Console.ReadLine();
}

class Data
{
    public Data(string l1, string k1, string l2, string k2, string l3, string k3)
    {
        L1 = l1; Key_L1 = k1;
        L2 = l2; Key_L2 = k2;
        L3 = l3; Key_L3 = k3;
    }
    public string L1 { get; set; }
    public string Key_L1 { get; set; }
    public string L2 { get; set; }
    public string Key_L2 { get; set; }
    public string L3 { get; set; }
    public string Key_L3 { get; set; }
}

上面是使用POCOs技术的工作示例。
您提到“datatable”; 我假设这是指.NET DataTable?如果是这样,您可以使用LINQ查询DataTable。您只需要使用DataSetExtensions将其转换为可枚举的。请参见:在DataTable上使用LINQ查询 然后在LINQ语句中,您用数据表替换列表.AsEnumerable(),并用.Field<string>("")替换属性引用。就像这样:
DataTable dt = // load data table
var tree = from l1 in dt.AsEnumerable()
           group l1 by new { key = l1.Field<string>("Key_L1"), name = l1.Field<string>("L1") } into group1
           select new
           {
               // etc.
           };

对于变量数量的列,您需要使用递归方法,如下所示:

var tree = Descend(dt.AsEnumerable(), 1, 3);

private static System.Collections.IEnumerable Descend(IEnumerable<DataRow> data, int currentLevel, int maxLevel)
{
    if (currentLevel > maxLevel)
    {
        return Enumerable.Empty<object>();
    }
    return from item in data
            group item by new
            {
                key = item.Field<string>("Key_L" + currentLevel),
                name = item.Field<string>("L" + currentLevel)
            } into rowGroup
            select new
            {
                key = rowGroup.Key.key,
                name = rowGroup.Key.name,
                children = Descend(rowGroup, currentLevel + 1, maxLevel)
            };
}

需要注意的一点是,这种方法会在叶节点上创建一个空的children集合。


谢谢!!!是的,我在谈论使用 .net datatable 类。我只是想知道是否可以使其更动态以选择多个类别。 - OpenStack
我想利用 .net DataTable 类,这样我就不必自己创建结构(在这种情况下是数据类)。你能否提供一个包含 DataTable 的示例呢? - OpenStack
@OpenStack 你看过 LINQ-to-DataTable 的文章吗?无论如何,我包含了一个简短的例子。 - Jack A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接