Json.net如何支持DataSet DataTable.

http://www.cnblogs.com/usharei/archive/2012/04/20/2458858.html

I've been thinking about replacing the JSON serializer in my internal codebase for some time and finally put a little effort into allowing JSON.NET fromJames Newton King to be plugged into my Ajax framework as a replaceable engine. My own parser has served me well, but JSON.NET is a much cleaner design and more flexible especially when dealing with extensibility. There are also a few nice features like the ability to pretty-format the generated JSON for debugging purposes which is immensely helpful when sending data to the client during development.

Although I'm keeping my original parser class (including original basic functionality) JSON.NET can now be optionally plugged in. So why not just replace the parser altogether? As it turns out I've been experimenting with different JSON serializer/deserializers and being able to keep a 'high level' wrapper object into which each of these parsers can be plugged into has been a great time saver as the interface that various application components use doesn't change one bit which is nice indeed.

Anyway, here's the basic code to provide JSON encoding and deserialization in a simple wrapper functions:

public string Serialize(object value)
{
    Type type = value.GetType();

    Newtonsoft.Json.JsonSerializer json = new Newtonsoft.Json.JsonSerializer();

    json.NullValueHandling = NullValueHandling.Ignore;
    
    json.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
    json.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
    json.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    if (type == typeof(DataRow))            
        json.Converters.Add(new DataRowConverter());
    else if(type == typeof(DataTable))
        json.Converters.Add(new DataTableConverter());
    else if (type == typeof(DataSet))
        json.Converters.Add(new DataSetConverter());
    
    StringWriter sw = new StringWriter();
    Newtonsoft.Json.JsonTextWriter writer = new JsonTextWriter(sw);
    if (this.FormatJsonOutput)
        writer.Formatting = Formatting.Indented;
    else
        writer.Formatting = Formatting.None;

    writer.QuoteChar = '"';
    json.Serialize(writer, value);
    
    string output = sw.ToString();
    writer.Close(); 
    sw.Close();
    
    return output;
}

public object Deserialize(string jsonText, Type valueType)
{
    Newtonsoft.Json.JsonSerializer json = new Newtonsoft.Json.JsonSerializer();
    
    json.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
    json.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
    json.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
    json.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

    StringReader sr = new StringReader(jsonText);
    Newtonsoft.Json.JsonTextReader reader = new JsonTextReader(sr);            
    object result = json.Deserialize(reader, valueType);
    reader.Close();

    return result;
}

One of the nice things about the JSON.NET parser is that there are a tons of configuration options that allow you to customize how JSON parsing occurs. You can see some of the options above for things like null value handling and managing how deep recursive loops should be handled for example.

JSON.NET also has a simplified JavaScriptConvert class that has much simpler serialization and deserialization methods, but this wrapper doesn't have access to the configuration options, so creating a custom wrapper that does exactly what I need certainly helps. As you can see above the parser has a ton of control over how many parsing aspects are handled which is really cool.

The really nice thing though - and the thing that really is missing in my parser - is extensibility. You can create custom Converters that can be plugged into the parsing pipeline to serialize and optionally deserialize custom types. Any JSON parser is likely to do well with most common types, but there may also be custom types or structures that are not supported or not well supported. For example, the ADO.NET objects, or a less obvious problem of how IDictionary types are handled (JSON.NET only supports string keys and then only those that result in valid JavaScript property/map names).

Luckily you can create your own converters, which is a common way of extensibility. The ASP.NET JavaScriptSerializer also supports extension via Converters. So, my immediate need before I could use the JSON.NET parser for a couple of old apps was to create a parser that can serialize JSON from Datatables.

Here's are a few converters that can create DataSet/DataTable and DataRow JSON with JSON.NET and turns them into simple value arrays (ie Dataset.Tables[].Rows[]).  Note the converters are only for serialization not deserialization:

/// <summary>
/// Converts a <see cref="DataRow"/> object to and from JSON.
/// </summary>
public class DataRowConverter : JsonConverter
{
    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    public override void WriteJson(JsonWriter writer, object dataRow)
    {
        DataRow row = dataRow as DataRow;

        // *** HACK: need to use root serializer to write the column value
        //     should be fixed in next ver of JSON.NET with writer.Serialize(object)
        JsonSerializer ser = new JsonSerializer();                        

        writer.WriteStartObject();
        foreach (DataColumn column in row.Table.Columns)
        {
            writer.WritePropertyName(column.ColumnName);
            ser.Serialize(writer,row[column]);
        }
        writer.WriteEndObject();
    }

    /// <summary>
    /// Determines whether this instance can convert the specified value type.
    /// </summary>
    /// <param name="valueType">Type of the value.</param>
    /// <returns>
    ///     <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type valueType)
    {
        return typeof(DataRow).IsAssignableFrom(valueType);
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>The object value.</returns>
    public override object ReadJson(JsonReader reader, Type objectType)
    {
        throw new NotImplementedException();
    }
}


/// <summary>
/// Converts a DataTable to JSON. Note no support for deserialization
/// </summary>
public class DataTableConverter : JsonConverter
{
    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    public override void WriteJson(JsonWriter writer, object dataTable)
    {
        DataTable table = dataTable as DataTable;
        DataRowConverter converter = new DataRowConverter();

        writer.WriteStartObject();

        writer.WritePropertyName("Rows");
        writer.WriteStartArray();
        
        foreach (DataRow row in table.Rows)
        {
            converter.WriteJson(writer, row);
        }

        writer.WriteEndArray();
        writer.WriteEndObject();
    }

    /// <summary>
    /// Determines whether this instance can convert the specified value type.
    /// </summary>
    /// <param name="valueType">Type of the value.</param>
    /// <returns>
    ///     <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type valueType)
    {
        return typeof(DataTable).IsAssignableFrom(valueType);
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>The object value.</returns>
    public override object ReadJson(JsonReader reader, Type objectType)
    {
        throw new NotImplementedException();
    }
}

/// <summary>
/// Converts a <see cref="DataSet"/> object to JSON. No support for reading.
/// </summary>
public class DataSetConverter : JsonConverter
{
    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    public override void WriteJson(JsonWriter writer, object dataset)
    {
        DataSet dataSet = dataset as DataSet;
        
        DataTableConverter converter = new DataTableConverter();

        writer.WriteStartObject();

        writer.WritePropertyName("Tables");
        writer.WriteStartArray();

        foreach (DataTable table in dataSet.Tables)
        {
            converter.WriteJson(writer, table);
        }
        writer.WriteEndArray();
        writer.WriteEndObject();
    }

    /// <summary>
    /// Determines whether this instance can convert the specified value type.
    /// </summary>
    /// <param name="valueType">Type of the value.</param>
    /// <returns>
    ///     <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type valueType)
    {
        return typeof(DataSet).IsAssignableFrom(valueType);
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>The object value.</returns>
    public override object ReadJson(JsonReader reader, Type objectType)
    {
        throw new NotImplementedException();
    }
}

Maybe somebody else will find this useful as well. The serialization is one way only because I personally don't have any need for two-way and deserialization of these objects is tricky because deserialization requires a type to match properties to values in the parsed JSON and well these ADO structures don't have any type format.

Anyway JSON.NET is really nice because it's highly configurable and actively developed. It's also open code so you can look through it and see how its done and tweak if necessary. One thing though - it appears it is a bit slower than other solutions. I've found JSON.NET 2.0 to be more than twice as slow as other solutions, and JSON.NET 3.0 as much as 6 to 7 times slower in some informal iteration tests built into my test suite (I noticed this because tests were slowing down drastically on the perf loop). While processing times are still very small (7 seconds for 10,000 serializations w/ JN 3.0) it still rankles a bit when its considerably slower than other solutions.

DataSet/DataTable/DataRow Serialization in JavaScriptSerializer

The stock JavaScriptSerializer that ships with System.Web.Extensions as part of .NET 3.5 also doesn't directly support ADO.NET objects. Some time ago there was a Converter provided in the Futures package (might still be but I haven't checked) but I never actually used it because the Futures assembly is just too much in flux and you never know what sticks around and will get axed.

Luckily it's also pretty easy to create custom converters for JavaScriptSerializer and so it's easy to create DataSet/Table/Row converters that you can add to your own apps without having to rely on the futures DLL. Here's that same implementation for the JavaScriptSerializer:

internal class WebExtensionsJavaScriptSerializer : JSONSerializerBase, IJSONSerializer
{
    public WebExtensionsJavaScriptSerializer(JSONSerializer serializer) : base(serializer)
    {}
  
    public string Serialize(object value)
    {
        JavaScriptSerializer ser = new JavaScriptSerializer();

        List<JavaScriptConverter> converters = new List<JavaScriptConverter>();

        if (value != null)
        {
            Type type = value.GetType();
            if (type == typeof(DataTable) || type == typeof(DataRow) || type == typeof(DataSet))
            {
                converters.Add(new WebExtensionsDataRowConverter());
                converters.Add(new WebExtensionsDataTableConverter());
                converters.Add(new WebExtensionsDataSetConverter());
            }

            if (converters.Count > 0)
                ser.RegisterConverters(converters);
        }
        
        return = ser.Serialize(value);
    }
    public object Deserialize(string jsonText, Type valueType)
    {
        // *** Have to use Reflection with a 'dynamic' non constant type instance
        JavaScriptSerializer ser = new JavaScriptSerializer();

        
        object result = ser.GetType()
                           .GetMethod("Deserialize")
                           .MakeGenericMethod(valueType)
                          .Invoke(ser, new object[1] { jsonText });
        return result;
    }
}



internal class WebExtensionsDataTableConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new Type[] {typeof (DataTable)}; }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type,
                                       JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
 

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        DataTable table = obj as DataTable;

        // *** result 'object'
        Dictionary<string, object> result = new Dictionary<string, object>();

        if (table != null)
        {
            // *** We'll represent rows as an array/listType
            List<object> rows = new List<object>();

            foreach (DataRow row in table.Rows)
            {
                rows.Add(row);  // Rely on DataRowConverter to handle
            }
            result["Rows"] = rows;

            return result;
        }

        return new Dictionary<string, object>();
    }
}

internal class WebExtensionsDataRowConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new Type[] { typeof(DataRow) }; }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type,
                                       JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        DataRow dataRow = obj as DataRow;
        Dictionary<string, object> propValues = new Dictionary<string, object>();                    

        if (dataRow != null)
        {
            foreach (DataColumn dc in dataRow.Table.Columns)
            {
                propValues.Add( dc.ColumnName, dataRow[dc]);
            }
        }

        return propValues;
    }
}

internal class WebExtensionsDataSetConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new Type[] { typeof(DataSet) }; }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type,
                                       JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        DataSet dataSet = obj as DataSet;
        Dictionary<string, object> tables = new Dictionary<string, object>();

        if (dataSet != null)
        {
            foreach (DataTable dt in dataSet.Tables)
            {
                tables.Add(dt.TableName, dt);
            }
        }

        return tables;
    }
}

Implementing a custom converter involves creating dictionaries of property name and value pairs with the abillity to create nested properties by specifying another dictionary as a value. This approach is makes it pretty easy to create custom serialization formats...

I know I'm not using DataSets much anymore these days but with older code still sitting around that does these converters are coming in handy. Maybe this will prove useful to some of you in a similar situation.

http://www.west-wind.com/weblog/posts/2008/Sep/03/DataTable-JSON-Serialization-in-JSONNET-and-JavaScriptSerializer


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在VB.NET中,可以使用DataSet的Copy方法将DataSet中的数据复制到一个新的DataTable中。具体的代码如下所示: ```vb Dim dataSet As New DataSet() ' 假设ordersTable是已经填充好数据的DataTable Dim ordersTable As DataTable = dataSet.Tables("Orders") ' 创建一个新的DataTable,并将ordersTable中的数据复制到新的DataTable中 Dim newDataTable As DataTable = ordersTable.Copy() ``` 通过调用Copy方法,可以将DataSet中的数据复制到一个新的DataTable中,然后可以对新的DataTable进行操作。\[2\] 需要注意的是,如果你只是想在代码中使用DataTable,而不需要使用DataSet,可以直接从数据库中获取数据并填充到DataTable中,而不需要使用DataSet。你可以使用ADO.NET提供的SqlConnection和SqlDataAdapter类来实现这个功能。具体的代码如下所示: ```vb Dim connStr As String = "Data Source=PC-201104071256\sqlEXPRESS;Initial Catalog=Northwind;Integrated Security=True" Dim conn As New SqlConnection(connStr) Dim sql As String = "SELECT * FROM Orders" Dim adapter As New SqlDataAdapter(sql, conn) Dim dataTable As New DataTable() adapter.Fill(dataTable) ``` 通过使用SqlConnection和SqlDataAdapter类,可以连接到数据库并执行查询,然后将查询结果填充到DataTable中。\[3\] #### 引用[.reference_title] - *1* *2* [VB.Net DataSetDataTable](https://blog.csdn.net/wulingmin21/article/details/6888461)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [vb.net中从datatable读取数据到Excel](https://blog.csdn.net/weixin_35651102/article/details/117833978)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值