.net 将数据行转换为JSON对象

mf98qq94  于 2023-03-31  发布在  .NET
关注(0)|答案(4)|浏览(207)

我有一个DataTable,它只有一行,看起来像

America              |  Africa               |     Japan     |   
   -------------------------------------------------------------
  {"Id":1,"Title":"Ka"} | {"Id":2,"Title":"Sf"} | {"Id":3,"Title":"Ja","Values":{"ValID":4,"Type":"Okinawa"}}

DataTable列是美洲、非洲、日本。
现在我想将DataTable转换为JSON,这样JSON看起来就像

{
"America": {
    "Id": 1,
    "Title": "Ka"
},
"Africa": {
    "Id": 2,
    "Title": "Sf"
},
"Japan": {
    "Id": 3,
    "Title": "Ja",
    "Values": {
        "ValID": 4,
        "Type": "Okinawa"
    }
  }
}

我的尝试是:

string js = JSonConvverter.Serializeobject(datatable);
var objType =  JObject.Parse(js);

但没成功任何帮助都将不胜感激。

vmdwslir

vmdwslir1#

假设您使用的是json.net,有一个特殊的内置转换器DataTableConverter,它将abbreviated format中的数据表输出为一个行数组,其中每行序列化为列名/值对,如您的问题所示。DataRow没有特定的内置转换器。因此,当直接序列化DataRow时,Json.NET将序列化DataRow的所有字段和属性,从而导致更详细的输出-而你不想这样

DataTable使用的更紧凑的形式序列化DataRow的最直接的方法是使用JArray.FromObject()将整个表序列化为JArray,然后选择与要序列化的DataRow具有相同索引的数组项:

var rowIndex = 0;

var jArray = JArray.FromObject(datatable, JsonSerializer.CreateDefault(new JsonSerializerSettings { /* Add settings as required e.g. */ NullValueHandling = NullValueHandling.Ignore }));

var rowJToken = jArray[rowIndex];
var rowJson = rowJToken.ToString(Formatting.Indented);  // Or Formatting.None if you prefer

因为你的表只有一行,所以rowIndex应该是0。更一般地说,如果你不知道给定DataRow的索引,请参阅 * How to get the row number from a datatable? *。
这对于只有一行的表应该很好,但通常不会有很好的性能。
演示小提琴#1 here

或者,如果表的行多列少,可以使用LINQ将行转换为Dictionary<string, object>,然后序列化:

var rowJson = JsonConvert.SerializeObject(
    row.Table.Columns.Cast<DataColumn>()
        .ToDictionary(c => c.ColumnName, c => row.IsNull(c) ? null : row[c]), 
    Formatting.Indented);

只要列数不多,性能应该不会太差。
小提琴#2 here

序列化一行最高效的方式是为DataRow引入一个custom JsonConverter,将行作为对象写入JSON:

public class DataRowConverter : JsonConverter<DataRow>
{
    public override DataRow ReadJson(JsonReader reader, Type objectType, DataRow existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException(string.Format("{0} is only implemented for writing.", this));
    }

    public override void WriteJson(JsonWriter writer, DataRow row, JsonSerializer serializer)
    {
        var table = row.Table;
        if (table == null)
            throw new JsonSerializationException("no table");
        var contractResolver = serializer.ContractResolver as DefaultContractResolver;

        writer.WriteStartObject();
        foreach (DataColumn col in row.Table.Columns)
        {
            var value = row[col];

            if (serializer.NullValueHandling == NullValueHandling.Ignore && (value == null || value == DBNull.Value))
                continue;
            
            writer.WritePropertyName(contractResolver != null ? contractResolver.GetResolvedPropertyName(col.ColumnName) : col.ColumnName);
            serializer.Serialize(writer, value);
        }
        writer.WriteEndObject();
    }
}

然后像这样使用它:

var settings = new JsonSerializerSettings
{
    Converters = { new DataRowConverter() },
    // Add other settings as required.
};
var rowJson = JsonConvert.SerializeObject(row, Formatting.Indented, settings);

备注:

  • 虽然序列化一个DataRow是有意义的,但是反序列化一个DataRow是没有意义的,因为DataRow不是一个独立的对象;它只存在于某个父DataTable中。因此ReadJson()没有实现。
  • JsonConverter<T>在Json.NET 11.0.1中引入。在早期版本中继承自JsonConverter

演示小提琴#3 here

yfjy0ee7

yfjy0ee72#

作为找到here的答案的替代方案,您可以使用ExpandoObject快速且非常容易地将单行呈现为JSON,如下所示:

var expando = new System.Dynamic.ExpandoObject() as IDictionary<string, object>;
foreach (DataColumn col in myRow.Table.Columns)
{
    expando[col.ColumnName] = myRow[col];
}
var json = JsonConvert.SerializeObject(expando);
mfpqipee

mfpqipee3#

拼写?对“SerializeObject”方法的调用不应该是:

string js = JsonConvert.SerializeObject(datatable);

另请参阅有关转换datatable to JSON string的类似问题。

vs3odd8k

vs3odd8k4#

就像Gazzi说的,你应该包括NewtonSoft.Json库,它包含在Visual Studio中。
要获得类似于您所描述的对象,您应该创建一个类似Country.cs的数据模型,如下所示。

[Serializable]
public class CountryModel {
   public int ID { get; set; }
   public string Title { get; set; }
   public List<ValueModel> Values { get; set; }
}

[Serializable]
public class ValueModel {
   public int ValueID { get; set; }
   public string Type { get; set; }
}

创建一个helper函数来将表数据转换为这些模型。然后您可以使用Newtonsoft库根据需要序列化/反序列化数据。

相关问题