How can I deserialize an ADO.NET DataTable that contains null values using Json.NET?

爷,独闯天下 提交于 2019-12-11 06:25:11

问题


I am attempting to use Newtonsoft.Json.Net35 Version 4.0.2.0 to deserialize an ADO.NET DataTable that contains null values. Serialization works fine:

    [Test]
    public void SerializeDataTableWithNull()
    {
        var table = new DataTable();
        table.Columns.Add("item");
        table.Columns.Add("price", typeof(double));
        table.Rows.Add("shirt", 49.99);
        table.Rows.Add("pants", 54.99);
        table.Rows.Add("shoes"); // no price

        var json = JsonConvert.SerializeObject(table);
        Assert.AreEqual(@"["
            + @"{""item"":""shirt"",""price"":49.99},"
            + @"{""item"":""pants"",""price"":54.99},"
            + @"{""item"":""shoes"",""price"":null}]", json);
    }

Deserialization works fine if values are missing:

    [Test]
    public void DerializeDataTableWithImplicitNull()
    {
        const string json = @"["
            + @"{""item"":""shirt"",""price"":49.99},"
            + @"{""item"":""pants"",""price"":54.99},"
            + @"{""item"":""shoes""}]";
        var table = JsonConvert.DeserializeObject<DataTable>(json);
        Assert.AreEqual("shirt", table.Rows[0]["item"]);
        Assert.AreEqual("pants", table.Rows[1]["item"]);
        Assert.AreEqual("shoes", table.Rows[2]["item"]);
        Assert.AreEqual(49.99, (double)table.Rows[0]["price"], 0.01);
        Assert.AreEqual(54.99, (double)table.Rows[1]["price"], 0.01);
        Assert.IsInstanceOf(typeof(System.DBNull), table.Rows[2]["price"]);
    }

If, however, values are explicitly null:

    [Test]
    public void DerializeDataTableWithExplicitNull()
    {
        const string json = @"["
            + @"{""item"":""shirt"",""price"":49.99},"
            + @"{""item"":""pants"",""price"":54.99},"
            + @"{""item"":""shoes"",""price"":null}]";
        var table = JsonConvert.DeserializeObject<DataTable>(json);
        Assert.AreEqual("shirt", table.Rows[0]["item"]);
        Assert.AreEqual("pants", table.Rows[1]["item"]);
        Assert.AreEqual("shoes", table.Rows[2]["item"]);
        Assert.AreEqual(49.99, (double)table.Rows[0]["price"], 0.01);
        Assert.AreEqual(54.99, (double)table.Rows[1]["price"], 0.01);
        Assert.IsInstanceOf(typeof(System.DBNull), table.Rows[2]["price"]);
    }

DeserializeObject throws "System.ArgumentException : Cannot set Column 'price' to be null. Please use DBNull instead." The following workaround works for my particular JSON:

        var regex = new Regex(@",?""[_\w]+"":null");
        var nullless = regex.Replace(json, string.Empty);
        var table = JsonConvert.DeserializeObject<DataTable>(nullless);

but like all regular expression-based kludges this is clearly brittle.

Finally, the questions:

  1. Is this a bug?
  2. Json.NET has many events that can be hooked. Is there a way to get notified when a when a null value is encountered and explicitly set the value to System.DBNull?

Thanks in advance,

Frank


回答1:


It looks like this is a bug which is easily fixed by replacing

dr[columnName] = reader.Value

with

dr[columnName] = reader.Value ?? System.DBNull.Value

in Newtonsoft.Json.Converters.DataTableConverter. I have entered an issue in the tracker.



来源:https://stackoverflow.com/questions/5902350/how-can-i-deserialize-an-ado-net-datatable-that-contains-null-values-using-json

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!