在C#中将datatable转换为JSON

103
  1. 我想从数据库中获取记录到一个DataTable中。
  2. 然后将DataTable转换为JSON对象。
  3. 将JSON对象返回给我的JavaScript函数。

我使用这个代码,通过调用:

string result = JsonConvert.SerializeObject(DatatableToDictionary(queryResult, "Title"), Newtonsoft.Json.Formatting.Indented);

将 DataTable 转换为 JSON,它可以正确工作并返回以下结果:

{
    "1": {
    "viewCount": 703,
    "clickCount": 98
    },
    "2": {
    "viewCount": 509,
    "clickCount": 85
    },
    "3": {
    "viewCount": 578,
    "clickCount": 86
    },
    "4": {
    "viewCount": 737,
    "clickCount": 108
    },
    "5": {
    "viewCount": 769,
    "clickCount": 130
    }
} 

但我希望它返回以下内容:

{"records":[
{
"Title": 1,
"viewCount": 703,
"clickCount": 98
},
{
"Title": 2,
"viewCount": 509,
"clickCount": 85
},
{
"Title": 3,
"viewCount": 578,
"clickCount": 86
},
{
"Title": 4,
"viewCount": 737,
"clickCount": 108
},
{
"Title": 5,
"viewCount": 769,
"clickCount": 130
}
]} 

我该怎么做?


可能是DataTable转JSON的重复问题。 - Evan Carroll
对于 .net core,还请参见 https://dev59.com/5kMEtIcB2Jgan1zn1l78。 - Rory
19个回答

206

这段来自C#,VB.NET中将DataTable转换为JSON字符串的代码片段 ,可能会对您有所帮助。它使用System.Web.Script.Serialization.JavaScriptSerializer 将内容序列化为JSON格式:

public string ConvertDataTabletoString()
{
    DataTable dt = new DataTable();
    using (SqlConnection con = new SqlConnection("Data Source=SureshDasari;Initial Catalog=master;Integrated Security=true"))
    {
        using (SqlCommand cmd = new SqlCommand("select title=City,lat=latitude,lng=longitude,description from LocationDetails", con))
        {
            con.Open();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(dt);
            System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
            Dictionary<string, object> row;
            foreach (DataRow dr in dt.Rows)
            {
                row = new Dictionary<string, object>();
                foreach (DataColumn col in dt.Columns)
                {
                    row.Add(col.ColumnName, dr[col]);
                }
                rows.Add(row);
            }
            return serializer.Serialize(rows);
        }
    }
}

如果我有两个数据表,需要将它们转换成一个JSON字符串,但是每个数据表都需要在JSON数组中,我该怎么做? - User7291
如何将此数据添加到表中? - Smith
9
您可以使用Json.Net代替JavaScriptSerializer:返回Newtonsoft.Json.JsonConvert.SerializeObject(rows)。 - Diego
5
对于我来说(.NET Framework 4.5),System.Web.Script 中的“Script”无法被识别/解析;而在“serializer.Serialize(rows)”中,“Serialize”也无法解析。 - B. Clay Shannon-B. Crow Raven

93
我们可以用两种简单的方法完成这个任务,一种是使用Json.NET dll,另一种是使用StringBuilder类。 使用Newtonsoft Json.NET
string JSONresult;
JSONresult = JsonConvert.SerializeObject(dt);  
Response.Write(JSONresult);

参考链接:Newtonsoft: Convert DataTable to JSON object in ASP.Net C#

使用 StringBuilder

public string DataTableToJsonObj(DataTable dt)
{
    DataSet ds = new DataSet();
    ds.Merge(dt);
    StringBuilder JsonString = new StringBuilder();
    if (ds != null && ds.Tables[0].Rows.Count > 0)
    {
        JsonString.Append("[");
        for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
        {
            JsonString.Append("{");
            for (int j = 0; j < ds.Tables[0].Columns.Count; j++)
            {
                if (j < ds.Tables[0].Columns.Count - 1)
                {
                    JsonString.Append("\"" + ds.Tables[0].Columns[j].ColumnName.ToString() + "\":" + "\"" + ds.Tables[0].Rows[i][j].ToString() + "\",");
                }
                else if (j == ds.Tables[0].Columns.Count - 1)
                {
                    JsonString.Append("\"" + ds.Tables[0].Columns[j].ColumnName.ToString() + "\":" + "\"" + ds.Tables[0].Rows[i][j].ToString() + "\"");
                }
            }
            if (i == ds.Tables[0].Rows.Count - 1)
            {
                JsonString.Append("}");
            }
            else
            {
                JsonString.Append("},");
            }
        }
        JsonString.Append("]");
        return JsonString.ToString();
    }
    else
    {
        return null;
    }
}

2
这个函数运行良好,但如何处理DataTable行字段中的双引号。 - Pranay Soni
JsonString方法因某种原因大约比SerializeObject快两倍...在处理大型数据集时性能也不是很好。 - hajikelist
这段代码很好,但是直接从数据表参数中读取数据会更快,而不是创建另一个变量。 - ayanix
这不是一个好的解决方案。首先,如果您的数据库中有任何带引号字符的值,它将失败。最好使用Newtonsoft包中的JsonTextWriter。 - statictype
使用Newtonsoft Json.NET可能是我认为最简单和最好的解决方案。 - user5328504

29

这种方法与被接受的答案类似,但使用LINQ将数据表转换为单行代码中的列表。

//convert datatable to list using LINQ. Input datatable is "dt", returning list of "name:value" tuples
var lst = dt.AsEnumerable()
    .Select(r => r.Table.Columns.Cast<DataColumn>()
            .Select(c => new KeyValuePair<string, object>(c.ColumnName, r[c.Ordinal])
           ).ToDictionary(z=>z.Key,z=>z.Value)
    ).ToList();
//now serialize it
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return serializer.Serialize(lst);

这是一种非常有用的方法,可以枚举数据表格,如果按照通常的方式需要大量编码!以下是一些变化:

//convert to list with array of values for each row
var list1 = dt.AsEnumerable().Select(r => r.ItemArray.ToList()).ToList();

//convert to list of first column values only
var list2 = dt.AsEnumerable().Select(r => r.ItemArray[0]).ToList();

// parse a datatable with conditions and get CSV string
string MalesOver21 = string.Join(",",
    dt.AsEnumerable()
      .Where(r => r["GENDER"].ToString()=="M" && r.Field<int>("AGE")>21)
      .Select(r => r.Field<string>("FULLNAME"))
 );

这个话题与原问题无关,但为了完整起见,我会提到如果您只想从现有的数据表中过滤掉行,请参见此答案


如果我使用了这段代码,那么我需要在视图上放置什么来显示JSON数据? - Jamie
1
这是一个非常开放式的问题。您可以使用许多JavaScript框架和工具来解析发送到视图的数据,例如JQgrid。或者您可以使用JavaScript使用For循环解析列表,并手动使用html构建表格。在我的最后一个例子中,我将结果连接成了一个字符串。您可以在C#中构建一个html表格或列表,然后返回内容。 - Vijay Jagdale
好的,谢谢。最终我使用了jQuery自动完成小部件来显示列表。你的代码帮了我很多,谢谢! :) - Jamie

20

不使用JavaScript序列化器的替代方法:

    public static string DataTableToJSON(DataTable Dt)
            {
                string[] StrDc = new string[Dt.Columns.Count];

                string HeadStr = string.Empty;
                for (int i = 0; i < Dt.Columns.Count; i++)
                {

                    StrDc[i] = Dt.Columns[i].Caption;
                    HeadStr += "\"" + StrDc[i] + "\":\"" + StrDc[i] + i.ToString() + "¾" + "\",";

                }

                HeadStr = HeadStr.Substring(0, HeadStr.Length - 1);

                StringBuilder Sb = new StringBuilder();

                Sb.Append("[");

                for (int i = 0; i < Dt.Rows.Count; i++)
                {

                    string TempStr = HeadStr;

                    for (int j = 0; j < Dt.Columns.Count; j++)
                    {

                        TempStr = TempStr.Replace(Dt.Columns[j] + j.ToString() + "¾", Dt.Rows[i][j].ToString().Trim());
                    }
                    //Sb.AppendFormat("{{{0}}},",TempStr);

                    Sb.Append("{"+TempStr + "},");
                }

                Sb = new StringBuilder(Sb.ToString().Substring(0, Sb.ToString().Length - 1));

                if(Sb.ToString().Length>0)
                Sb.Append("]");

                return StripControlChars(Sb.ToString());

            }
//To strip control characters:

//A character that does not represent a printable character but //serves to initiate a particular action.

            public static string StripControlChars(string s)
            {
                return Regex.Replace(s, @"[^\x20-\x7F]", "");
            }

1
请问我为什么被踩了?这是一个可用的代码片段...它正在生产环境中使用。 - Durai Amuthan.H
1
可能是因为您手动创建了JSON结构,而您可以使用更面向对象的方法。这种方式非常混乱。 - Josh M.
6
我的回答旨在展示另一种处理问题的方法。 - Durai Amuthan.H
5
有些直觉告诉我,一个程序员应该能够编写代码并且使用第三方工具,而编写自定义代码可能比使用臃肿的工具更好完成这个简单的任务。 - Adam Heeg
这是很久以前写的了,但作为一个厌恶使用第三方库的人,我喜欢这个。手动完成它是我最喜欢的方法,因为你可以更好地控制应用程序。而且,仅仅因为你手动完成它并不意味着它不是“面向对象”的。只需在目录中创建另一个类并像导入一样使用它即可解决。做得好! - FastFinge

14

现在非常简单..

string json = JsonConvert.SerializeObject(YourDataTable, Formatting.Indented);
现在将您的Json转换为DataTable:
YourDataTable = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));

也适用于数据集。


6

您可以使用 Alireza Maddah 指定的相同方法,如果您想将两个数据表用于一个 JSON 数组,则可以按照以下方式进行:

public string ConvertDataTabletoString()
{
DataTable dt = new DataTable();
DataTable dt1 = new DataTable();
using (SqlConnection con = new SqlConnection("Data Source=SureshDasari;Initial Catalog=master;Integrated Security=true"))
{
    using (SqlCommand cmd = new SqlCommand("select title=City,lat=latitude,lng=longitude,description from LocationDetails", con))
    {
        con.Open();
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        da.Fill(dt);
        System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
        Dictionary<string, object> row;
        foreach (DataRow dr in dt.Rows)
        {
            row = new Dictionary<string, object>();
            foreach (DataColumn col in dt.Columns)
            {
                row.Add(col.ColumnName, dr[col]);
            }
            rows.Add(row);
        }
        SqlCommand cmd1 = new SqlCommand("_another_query_", con);
                SqlDataAdapter da1 = new SqlDataAdapter(cmd1);
                da1.Fill(dt1);
                System.Web.Script.Serialization.JavaScriptSerializer serializer1 = new System.Web.Script.Serialization.JavaScriptSerializer();
                Dictionary<string, object> row1;
                foreach (DataRow dr in dt1.Rows) //use the old variable rows only
                {
                    row1 = new Dictionary<string, object>();
                    foreach (DataColumn col in dt1.Columns)
                    {
                        row1.Add(col.ColumnName, dr[col]);
                    }
                    rows.Add(row1); // Finally You can add into old json array in this way
                }
        return serializer.Serialize(rows);
    }
}
}

同样的方法可以用于您想要的任何数据表。

5
使用C#.net将数据表转换为JSON
 public static object DataTableToJSON(DataTable table)
    {
        var list = new List<Dictionary<string, object>>();

        foreach (DataRow row in table.Rows)
        {
            var dict = new Dictionary<string, object>();

            foreach (DataColumn col in table.Columns)
            {
                dict[col.ColumnName] = (Convert.ToString(row[col]));
            }
            list.Add(dict);
        }
        JavaScriptSerializer serializer = new JavaScriptSerializer();

        return serializer.Serialize(list);
    }

3

尝试使用这个自定义函数。

    public static string DataTableToJsonObj(DataTable dt)
    {
        DataSet ds = new DataSet();
        ds.Merge(dt);
        StringBuilder jsonString = new StringBuilder();

        if (ds.Tables[0].Rows.Count > 0)
        {
            jsonString.Append("[");
            for (int rows = 0; rows < ds.Tables[0].Rows.Count; rows++)
            {
                jsonString.Append("{");
                for (int cols = 0; cols < ds.Tables[0].Columns.Count; cols++)
                {
                    jsonString.Append(@"""" + ds.Tables[0].Columns[cols].ColumnName + @""":");

                    /* 
                    //IF NOT LAST PROPERTY

                    if (cols < ds.Tables[0].Columns.Count - 1)
                    {
                        GenerateJsonProperty(ds, rows, cols, jsonString);
                    }

                    //IF LAST PROPERTY

                    else if (cols == ds.Tables[0].Columns.Count - 1)
                    {
                        GenerateJsonProperty(ds, rows, cols, jsonString, true);
                    }
                    */

                    var b = (cols < ds.Tables[0].Columns.Count - 1)
                        ? GenerateJsonProperty(ds, rows, cols, jsonString)
                        : (cols != ds.Tables[0].Columns.Count - 1)
                          || GenerateJsonProperty(ds, rows, cols, jsonString, true);
                }
                jsonString.Append(rows == ds.Tables[0].Rows.Count - 1 ? "}" : "},");
            }
            jsonString.Append("]");
            return jsonString.ToString();
        }
        return null;
    }

    private static bool GenerateJsonProperty(DataSet ds, int rows, int cols, StringBuilder jsonString, bool isLast = false)
    {

        // IF LAST PROPERTY THEN REMOVE 'COMMA'  IF NOT LAST PROPERTY THEN ADD 'COMMA'
        string addComma = isLast ? "" : ",";

        if (ds.Tables[0].Rows[rows][cols] == DBNull.Value)
        {
            jsonString.Append(" null " + addComma);
        }
        else if (ds.Tables[0].Columns[cols].DataType == typeof(DateTime))
        {
            jsonString.Append(@"""" + (((DateTime)ds.Tables[0].Rows[rows][cols]).ToString("yyyy-MM-dd HH':'mm':'ss")) + @"""" + addComma);
        }
        else if (ds.Tables[0].Columns[cols].DataType == typeof(string))
        {
            jsonString.Append(@"""" + (ds.Tables[0].Rows[rows][cols]) + @"""" + addComma);
        }
        else if (ds.Tables[0].Columns[cols].DataType == typeof(bool))
        {
            jsonString.Append(Convert.ToBoolean(ds.Tables[0].Rows[rows][cols]) ? "true" : "fasle");
        }
        else
        {
            jsonString.Append(ds.Tables[0].Rows[rows][cols] + addComma);
        }

        return true;
    }

在此之后,您可以像这样对数组进行反序列化。 var deserializeArray = new JavaScriptSerializer().Deserialize<dynamic>(desrilizeDashboard); - Hasan Javaid

3

所有这些回答都非常适用于移动数据!但它们无法保留移动的数据列类型,当你想合并看起来相同的数据表格时,这就成为了一个问题。 JsonConvert 会查看第一行数据以确定列的数据类型,这可能会被错误地猜测

要解决这个问题:

  • DataTableDataColumn定义序列化为单独的响应对象。
  • 在读取表格之前反序列化响应中的 DataColumn 定义。
  • 忽略 Json 定义的模式,反序列化和合并 DataTable

听起来很多,但只需要额外三行代码。

// Get our Column definitions and serialize them using an anoymous function.
var columns = dt.Columns.Cast<DataColumn>().Select(c => new { DataPropertyName = c.ColumnName, DataPropertyType = c.DataType.ToString()});
resp.ObjSchema = JsonConvert.SerializeObject(columns);
resp.Obj = JsonConvert.SerializeObject(dt);

resp.ObjSchema 变为:

[
  {
    "DataPropertyName": "RowId",
    "DataPropertyType ": "System.Int32"
  },
  {
    "DataPropertyName": "ItemName",
    "DataPropertyType ": "System.String"
  }
]

我们可以使用 LINQ 在 resp.ObjSchema 上定义列定义,而不是让 Json 通过 dt = JsonConvert.DeserializeObject<DataTable>(response) 来定义它们。我们将使用 MissingSchemaAction.Ignore 忽略 Json 提供的表结构。

// If your environment does not support dynamic you'll need to create a class for with DataPropertyName and DataPropertyType.
JsonConvert.DeserializeObject<List<dynamic>>(response.ObjSchema).ForEach(prop =>
{
    dt.Columns.Add(new DataColumn() { ColumnName = prop.DataPropertyName, DataType = Type.GetType(prop.DataPropertyType.ToString()) });
});
// Merge the results ignoring the JSON schema.
dt.Merge(JsonConvert.DeserializeObject<DataTable>(response.Obj), true, MissingSchemaAction.Ignore);

1
谢谢。我创建了一个基于你的答案的解决方案,只是将它们全部封装在一个类中。这样更容易,并且允许其他人简单地复制粘贴并使用。 - Michael Z.

2

要在Json方法中访问转换的数据表值,请按以下步骤操作:

$.ajax({
        type: "POST",
        url: "/Services.asmx/YourMethodName",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (data) {
            var parsed = $.parseJSON(data.d);
            $.each(parsed, function (i, jsondata) {
            $("#dividtodisplay").append("Title: " + jsondata.title + "<br/>" + "Latitude: " + jsondata.lat);
            });
        },
        error: function (XHR, errStatus, errorThrown) {
            var err = JSON.parse(XHR.responseText);
            errorMessage = err.Message;
            alert(errorMessage);
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接