序列化数据时创建树节点

Create a tree node when serializing data

我从 SQL 数据库中查询了一些数据,我使用此代码对它们进行序列化:

List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
DataTable dt = new DataTable();
...

SqlDataAdapter adapt = new SqlDataAdapter();
adapt.Fill(dt);

Dictionary<string, object> row;
foreach (DataRow dr in dt.Rows)
{
    row = new Dictionary<string, object>();
    foreach (DataColumn col in dt.Columns)
    {
        row.Add(col.ColumnName, dr[col]);
    }
    rows.Add(row);
}
return JsonSerializer.Serialize(rows);

当我序列化它们时,它给了我这个结果:

{
    "operator": "Unknown",
    "extrainfo": "potential client",
    "Name": "John Doe",
    "ID": 568910,
    "LastUpdate": "2021-07-22T00:00:00",      
    "Interested?": "Yes",
    "Does it have a valid contract?": "No",
    "Contract type": "Prepaid",
    "Client willing to pay more?": "Yes, up to 20%",       
    "Comments": {}
}

我希望 lastUpdate 列之后的所有数据在另一个节点内序列化,该节点简称为 interview。 这是我想要序列化它们的方式:

{
    "operator": "Unknown",
    "extrainfo": "potential client",
    "Name": "John Doe",
    "ID": 568910,
    "LastUpdate": "2021-07-22T00:00:00",          
    "interview": [
        {
            "question" : "Interested?",
            "answer": "Yes"
        },
        {
            "question" : "Does it have a valid contract?",
            "answer": "No"
        },
        {
            "question" : "Contract type",
            "answer": "Prepaid"
        },
        {
            "question" : "Client willing to pay more?",
            "answer": "Yes, up to 20%"
        },           
        {
            "question" : "Comments",
            "answer": ""
        }
    ]
}

这是数据库行的样子:

我需要有关如何执行此操作的帮助。

@admiri 请查看此 link 中的序列化示例 https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-5-0

All data that comes after lastUpdate column to be serialized inside another node

之后是相对的:

  • 您的 DataTable 可能会以不同的顺序定义列,然后它们应该出现在 json
  • 序列化程序可能使用与您的数据库架构不同的顺序

过滤

我会建议一种方法,您可以在其中列出应序列化为属性的字段,并将其余字段视为 interview 问答对。

var propertyFields = new[] { "operator", "extrainfo", "Name", "ID", "LastUpdate" };

正在捕获数据

为了创建所需的输出(对于 interview),您可能需要引入 classstruct我介绍了一个named ValueTuple to avoid creating such. But depending on your runtime environment it may or may not available. UPDATE: ValueTuples are not supported by System.Text.Json.JsonSerializer

struct Interview
{
    [JsonPropertyName("question")]
    public string Question { get; set; }
    [JsonPropertyName("answer")]
    public string Answer { get; set; }
}

接线

让我们把所有这些东西放在一起

static readonly string[] propertyFields = new[] { "operator", "extrainfo", "Name", "ID", "LastUpdate" };

...
Dictionary<string, object> row;
foreach (DataRow dr in dt.Rows)
{
    row = new Dictionary<string, object>();
    var interview = new List<Interview>();

    foreach (DataColumn col in dt.Columns)
    {
        string name = col.ColumnName;
        object value = dr[col];
        if (propertyFields.Contains(col.ColumnName))
            row.Add(name, value);
        else
            interview.Add(new Interview { Question = name, Answer = value.ToString() });

    }
    row.Add("interview", interview);
    rows.Add(row);
}

我用元组列表替换了 sql 数据。出于算法的目的,它将是相同的。

请注意,执行此操作的最简单方法是创建一个 POCO class 以使用嵌套的“inteview”POCO 保存实际值。如果这是来自 SQL 那么您应该知道列结构。

针对您的问题,我将假设无论出于何种原因,这是不可能的,并且您不提前知道列结构,而您是在即时执行此操作。

在这种情况下,您最好不要使用任何 POCO classes - 包括您当前正在使用的字典 - 只需将数据写为 JSON。一种方法如下:

    static List<(string name, string[] values)> Data = new()
    {
        ("operator", new[] { "Unknown" } ),
        ("extrainfo", new[] { "potential client" }),
        ("Name", new[] { "John Doe" }),
        ("ID", new[] { "568910" }),
        ("LastUpdate", new[] { "2021-07-22T00:00:00" }),
        ("Interested?", new[] { "Yes" } ),
        ("Does it have a valid contract?", new[] { "No" } ),
        ("Contract type", new[] { "Prepaid" } ),
        ("Client willing to pay more?", new[] { "Yes, up to 20%" } ),
        ("Comments", new string[] { }),
    };

    static string Serilize(List<(string name, string[] values)> data)
    {
        using var output = new MemoryStream();
        using (var writer = new Utf8JsonWriter(output, new JsonWriterOptions() { Indented = true }))
        {
            bool foundQA = false;

            writer.WriteStartObject();

            foreach (var row in data)
            {
                if (!foundQA)
                {
                    foreach (var value in row.values)
                    {
                        writer.WritePropertyName(row.name);

                        if (null != value)
                            writer.WriteStringValue(value);
                        else
                            writer.WriteStringValue("");
                    }

                    if (row.name == "LastUpdate")
                    {
                        writer.WritePropertyName("interview");
                        writer.WriteStartArray();
                        foundQA = true;
                    }
                }
                else
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName("question");
                    writer.WriteStringValue(row.name);

                    writer.WritePropertyName("answer");
                    writer.WriteStringValue(row.values.Length > 0 ? row.values[0] : "");

                    writer.WriteEndObject();
                }
            }

            if (foundQA)
            {
                writer.WriteEndArray();
            }

            writer.WriteEndObject();
        }

        return Encoding.UTF8.GetString(output.ToArray());
    }


    static void Main(string[] args)
    {
        string formattedJson = Serilize(Data);

        Console.WriteLine("Formatted output:");
        Console.WriteLine(formattedJson);
    }