序列化数据时创建树节点
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
),您可能需要引入 class
或 struct
。 我介绍了一个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);
}
我从 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
),您可能需要引入 class
或 struct
。 我介绍了一个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);
}