如何在JSON中为空DataTable包含列元数据

Ben*_*uri 4 c# datatable json json.net

如何在JSON中正确描述列元数据,以后由Newtonsoft解析以构建ac#DataTable,这样我希望解决一个问题,即获取没有行的DataTable,但也没有列我需要列的列当我传递一个空表时,使用标签创建并希望使用数据类型.

标准输入的示例:

{

"BrokerID" : "998",
"AccountID" : "1313",
"Packages":[
                  {

                    "PackageID": 226,
                    "Amount": 15000,
                    "Auto_sync": true,
                    "Color": "BLUE"

                  },
                  {

                    "PackageID": 500,
                    "Amount": 15000,
                    "Auto_sync": true,
                    "Color": "PEACH"

                  }

           ]
}
Run Code Online (Sandbox Code Playgroud)

输入空表的示例:{"BrokerID":"998","AccountID":"1313","包":[]}

当我使用解析时, JsonConvert.DeserializeObject<DataTable>(params["Packages"]);我没有得到任何行,显然没有列,我正在寻找一种方法来描述json主体中的列元数据.

Bri*_*ers 7

DataTableConverter附带Json.Net不输出列的元数据,即使你设置TypeNameHandlingAll.但是,没有什么可以阻止您制作自己的自定义转换器来执行此操作,而是使用它.这是我一起整理的,可能适合您的需求:

class CustomDataTableConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(DataTable));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        DataTable dt = (DataTable)value;
        JObject metaDataObj = new JObject();
        foreach (DataColumn col in dt.Columns)
        {
            metaDataObj.Add(col.ColumnName, col.DataType.AssemblyQualifiedName);
        }
        JArray rowsArray = new JArray();
        rowsArray.Add(metaDataObj);
        foreach (DataRow row in dt.Rows)
        {
            JObject rowDataObj = new JObject();
            foreach (DataColumn col in dt.Columns)
            {
                rowDataObj.Add(col.ColumnName, JToken.FromObject(row[col]));
            }
            rowsArray.Add(rowDataObj);
        }
        rowsArray.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JArray rowsArray = JArray.Load(reader);
        JObject metaDataObj = (JObject)rowsArray.First();
        DataTable dt = new DataTable();
        foreach (JProperty prop in metaDataObj.Properties())
        {
            dt.Columns.Add(prop.Name, Type.GetType((string)prop.Value, throwOnError: true));
        }
        foreach (JObject rowDataObj in rowsArray.Skip(1))
        {
            DataRow row = dt.NewRow();
            foreach (DataColumn col in dt.Columns)
            {
                row[col] = rowDataObj[col.ColumnName].ToObject(col.DataType);
            }
            dt.Rows.Add(row);
        }
        return dt;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个演示.请注意,在序列化表时,列类型将作为JSON中数组的第一行写出.在反序列化时,即使没有其他行,此元数据也用于使用正确的列类型和名称重新构建表.(您可以通过注释掉行数据添加到表格顶部的两行来验证这一点.)

class Program
{
    static void Main(string[] args)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("PackageID", typeof(int));
        dt.Columns.Add("Amount", typeof(int));
        dt.Columns.Add("Auto_sync", typeof(bool));
        dt.Columns.Add("Color", typeof(string));
        // Comment out these two lines to see the table with no data
        dt.Rows.Add(new object[] { 226, 15000, true, "BLUE" });
        dt.Rows.Add(new object[] { 500, 15000, true, "PEACH" });

        Foo foo = new Foo
        {
            BrokerID = "998",
            AccountID = "1313",
            Packages = dt
        };

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new CustomDataTableConverter());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(foo, settings);
        Console.WriteLine(json);
        Console.WriteLine();

        Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings);
        Console.WriteLine("BrokerID: " + foo2.BrokerID);
        Console.WriteLine("AccountID: " + foo2.AccountID);
        Console.WriteLine("Packages table:");
        Console.WriteLine("  " + string.Join(", ", 
            foo2.Packages.Columns
                .Cast<DataColumn>()
                .Select(c => c.ColumnName + " (" + c.DataType.Name + ")")));

        foreach (DataRow row in foo2.Packages.Rows)
        {
            Console.WriteLine("  " + string.Join(", ", row.ItemArray
                .Select(v => v != null ? v.ToString() : "(null)")));
        }
    }
}

class Foo
{
    public string BrokerID { get; set; }
    public string AccountID { get; set; }
    public DataTable Packages { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

输出:

{
  "BrokerID": "998",
  "AccountID": "1313",
  "Packages": [
    {
      "PackageID": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
      "Amount": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
      "Auto_sync": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
      "Color": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    },
    {
      "PackageID": 226,
      "Amount": 15000,
      "Auto_sync": true,
      "Color": "BLUE"
    },
    {
      "PackageID": 500,
      "Amount": 15000,
      "Auto_sync": true,
      "Color": "PEACH"
    }
  ]
}

BrokerID: 998
AccountID: 1313
Packages table:
  PackageID (Int32), Amount (Int32), Auto_sync (Boolean), Color (String)
  226, 15000, True, BLUE
  500, 15000, True, PEACH
Run Code Online (Sandbox Code Playgroud)

小提琴:https://dotnetfiddle.net/2TwpLf