【问题标题】:Convert a data row to a JSON object将数据行转换为 JSON 对象
【发布时间】:2016-01-28 17:45:28
【问题描述】:

我有一个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);

但它没有用。任何帮助将不胜感激。

【问题讨论】:

标签: c# .net json datatable


【解决方案1】:

假设您使用的是,则有一个特殊的内置转换器DataTableConverter,它将abbreviated format 中的数据表输出为一个行数组,其中每一行被序列化为列名/值对显示在您的问题中。虽然还有a converter for DataSet,但DataRow 没有特定的内置转换器。因此,当直接序列化 DataRow 时,Json.NET 将序列化 DataRow 的所有字段和属性,从而导致更冗长的输出 - 这是您不想要的。

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

var rowIndex = 0;

var jArray = JArray.FromObject(datatable, JsonSerializer.CreateDefault(new JsonSerializerSettings { 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.

或者,如果您的表足够大以至于序列化整个表会影响性能,您可以为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 row = datatable.Rows[rowIndex];

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    Converters = { new DataRowConverter() },
};
var rowJson = JsonConvert.SerializeObject(row, Formatting.Indented, settings);

注意事项:

  • 虽然序列化单个DataRow 是有意义的,但反序列化一个没有意义,因为DataRow 不是一个独立的对象;它只存在于某个父级DataTable 中。因此ReadJson() 没有实现。

  • JsonConverter&lt;T&gt; 在 Json.NET 11.0.1 中引入。在早期版本中,继承自 JsonConverter

演示小提琴 #2 here.

【讨论】:

    【解决方案2】:

    作为找到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);
    

    【讨论】:

      【解决方案3】:

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

      string js = JsonConvert.SerializeObject(datatable);
      

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

      【讨论】:

        【解决方案4】:

        就像 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; }
        }
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-13
          • 2021-11-18
          • 2017-05-04
          • 2017-06-16
          • 2012-07-21
          相关资源
          最近更新 更多