当前位置: 首页 > 面试题库 >

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

叶冥夜
2023-03-14
问题内容

我正在寻找适当地描述JSON中的列元数据的方法,稍后由Newtonsoft对其进行解析以构建C#DataTable。这样,我希望解决一个DataTable没有行或没有列的a的问题,但是即使我传递一个空表,我也需要使用标签和希望的数据类型来创建列。

标准输入的示例:

{
    "BrokerID": "998",
    "AccountID": "1313",
    "Packages": [
        {
            "PackageID": 226,
            "Amount": 15000,
            "Auto_sync": true,
            "Color": "BLUE"
        },
        {
            "PackageID": 500,
            "Amount": 15000,
            "Auto_sync": true,
            "Color": "PEACH"
        }
    ]
}

输入表为空的示例:

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

当我使用解析此内容时JsonConvert.DeserializeObject<DataTable>(params["Packages"]);,没有行,而且显然没有列。我正在寻找一种描述JSON正文中的列元数据的方法。


问题答案:

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)
            {
                if (rowDataObj[col.ColumnName].Type != JTokenType.Null)//Skip if the Value is Null/Missing, especially for a non-nullable type.
                    row[col] = rowDataObj[col.ColumnName].ToObject(col.DataType);
            }
            dt.Rows.Add(row);
        }
        return dt;
    }
}

这是一个演示。请注意,序列化表时,列类型被写为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.
        // Test with a null Value for a Non-Nullable DataType.
        dt.Rows.Add(new object[] { 226,  null, 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; }
}

输出:

{
  "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": null,
      "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, , True, BLUE
  500, 15000, True, PEACH

小提琴:https :
//dotnetfiddle.net/GGrn9z



 类似资料:
  • 我正在使用Jackson 2.4将对象序列化为JSON。 当我序列化对象列表时,如果某些元素为空,则结果字符串包含一些“空”字符串。 如何防止元素被序列化?是否有任何配置?我已经设置了! 下面是我的代码: 连载之后我得到了这个:

  • 我正在尝试将csv文件中的值映射到RDD,但我收到以下错误,因为某些字段为空。 线程"main"中的异常org.apache.spark.SparkException:由于阶段失败而中止的作业:阶段0.0中的任务0失败1次,最近的失败:阶段0.0中丢失的任务0.0(TID 0,localhost,执行驱动程序):java.lang.NumberFormatException:空字符串 以下是我正在

  • 编辑:应你们中一些人的要求,我发布了我的真实数据结构和类。我没能让你更容易理解这个问题。 我在解决JacksonJSON数组元素时遇到问题,最终出现异常,我将在本文后面报告。 我有一个来自第三方提供商的冗长的JSON字符串: 我的Java合奏如下。 这是最外层的容器: 这是第一级容器: 这是最里面的层次: 最后,这是我的反序列化代码: 在极端综合法中,我试图将问题概括如下: 类有一个模块成员,它是

  • 问题内容: 我有一个表,其中的列包含一些空值。我想在该列上添加约束,而不将现有的null更新为非null值。我想保留现有的空值,并检查将来的行,它们是否包含此列的非空值。这可能吗?如何? 问题答案: 您可以添加未验证的约束-它不会查看现有行,但是会检查是否有任何新行或更新行。 请注意,除非满足约束,否则您将无法更新现有行。 另外,请注意,不利之处在于,优化器在制定计划时将无法利用此约束-它必须假设

  • 因此,目前我正试图了解Java8。 我有这个流操作 但是,有时e.foo()可以是Null或e.bar()可以是null或e.baz()可以是null。 所以,我只想过滤那些事件,其中任何一个方法都会返回空值。 在Java8中,一种干净的方法是什么。

  • 问题内容: 我在将BigQuery(15亿行)中的大量数据表从行转换为列时遇到问题。我可以弄清楚在进行硬编码时如何处理少量数据,但处理量如此之大。该表的快照如下所示: 因此,基本上大约有400,000个具有3000个功能的不同的customerID,并且并非每个customerID都具有相同的功能,因此,某些customerID可能具有2000个功能,而有些具有3000个功能。并具有代表所有功能的