从 SqlDataReader 转换为 JSON

Posted

技术标签:

【中文标题】从 SqlDataReader 转换为 JSON【英文标题】:convert from SqlDataReader to JSON 【发布时间】:2011-07-02 07:22:04 【问题描述】:
public string toJSON(SqlDataReader o)

    StringBuilder s = new StringBuilder();
    s.Append("[");
    if (o.HasRows)
        while (o.Read())
            s.Append("" + '"' + "Id" + '"' + ":" + o["Id"] + ", "
            + '"' + "CN" + '"' + ":" + o["CatName"] + ", "
            + '"' + "Ord" + '"' + ":" + o["Ord"] + ","
            + '"' + "Icon" + '"' + ":" + o["Icon"] + ", ");
    s.Remove(s.Length - 2, 2);
    s.Append("]");
    o.Close();
    return s.ToString();

我在这里使用我自己的函数来进行序列化。我需要知道这是否是一个好方法,或者我应该使用另一个 .顺便说一句,我尝试使用 javascriptSerializer 但这不适用于 SqlDataReader 。谢谢

【问题讨论】:

学习使用string.Format,让您的生活更轻松。 那么StringBuilder.AppendFormat 呢?并使用逐字字符串文字(以@ 开头的文字)? 这可能会有所帮助。 thnx 但是你觉得这个功能好还是什么! 【参考方案1】:

如果您想要转换为任意 JSON 的内容,您可以通过将其序列化为 Dictionary(Of string, object) 来转换:

public IEnumerable<Dictionary<string, object>> Serialize(SqlDataReader reader)

    var results = new List<Dictionary<string, object>>();
    var cols = new List<string>();
    for (var i = 0; i < reader.FieldCount; i++) 
        cols.Add(reader.GetName(i));

    while (reader.Read()) 
        results.Add(SerializeRow(cols, reader));

    return results;

private Dictionary<string, object> SerializeRow(IEnumerable<string> cols, 
                                                SqlDataReader reader) 
    var result = new Dictionary<string, object>();
    foreach (var col in cols) 
        result.Add(col, reader[col]);
    return result;

然后使用 NewtonSoft.Json JsonConvert 对象来获取您的 JSON:

var r = Serialize(reader);
string json = JsonConvert.SerializeObject(r, Formatting.Indented);

更新: 如果您只想使用内置方法,而您恰好使用的是 MVC,则可以在新序列化时使用内置 Json 辅助方法:

JsonResult Index(int id) 
    var r = Serialize(reader);
    return Json(r, JsonRequestBehavior.AllowGet);

【讨论】:

这是替换使用 SqlDataSource 和 AutoGenerateColumns="True" 的旧 WebForms 代码的最佳解决方案,这正是我需要的!你为我节省了 5 分钟的编码时间。热爱互联网。 很高兴您发现它很有用。这也是我用它的目的。 :)【参考方案2】:

这应该可以完成工作

private String sqlDatoToJson(SqlDataReader dataReader)

    var dataTable = new DataTable();
    dataTable.Load(dataReader);
    string JSONString = string.Empty;
    JSONString = JsonConvert.SerializeObject(dataTable);
    return JSONString;

【讨论】:

需要通过 Nuget 添加 Newtonsoft.Json 才能使用JsonConvert dataTable.load(dataReader) 是否一次将整个结果集加载到内存中? 最佳答案在这里。 是的,这个答案很可能会一次将整个结果集加载到内存中。根据我目前的经验,它适用于小型结果集。【参考方案3】:

我遇到过数据读取器返回的行数可能会在内存消耗方面出现问题的用例。以下代码在流上使用 JsonWriter(来自 JSON.NET)。人们当然可以讨论大量 JSON 文档的效用,但有时我们的用例是由其他人决定的 :-)

几点说明:

我的 SqlDataReader 可能包含多个结果集(“表”) 我可能会将输出发送到 FileStream 或 HttpResponse 流 我已经“抽象”了我的对象名称以匹配每个结果集返回的第一列 由于可能产生大型结果集,我使用 SqlDataReader 的异步方法。 我让 JSON.NET 处理数据读取器结果中包含的实际数据的所有序列化问题。

代码:

var stream = ... // In my case, a FileStream or HttpResponse stream
using (var writer = new JsonTextWriter(new StreamWriter(stream)))

    writer.WriteStartObject();  
    do
    
        int row = 0;
        string firstColumn = null;
        while (await reader.ReadAsync())
        
            if (row++ == 0)
            
                firstColumn = reader.GetName(0);
                writer.WritePropertyName(string.Format("0Collection", firstColumn));
                writer.WriteStartArray();   
            
            writer.WriteStartObject();
            for (int i = 0; i < reader.FieldCount; i++)
            
                if (!reader.IsDBNull(i))  
                    writer.WritePropertyName(reader.GetName(i));
                    writer.WriteValue(reader.GetValue(i));
                
            
            writer.WriteEndObject(); 
        
        writer.WriteEndArray();
     while (await reader.NextResultAsync());

    writer.WriteEndObject();

异构输出的一个例子是:


    "ContactCollection": 
        "ContactItem": [
                "ContactID": "1",
                "Contact": "Testing",
            ,
            
                "ContactID": "2",
                "Contact": "Smith, John",
            ,
            
                "ContactID": "4",
                "Contact": "Smith, Jane",
            
        ],
        "MessageItem": [
                "MessageID": "56563",
                "Message": "Contract Review Changed",
            ,
            
                "MessageID": "56564",
                "Message": " Changed",
            ,
            
                "MessageID": "56565",
                "Message": "Contract Review - Estimated Completion Added.",
            
        ]
    

参考:

http://www.newtonsoft.com/json/help/html/Performance.htm

【讨论】:

最佳答案,在我看来。在我看来,其他答案在内存效率方面存在问题。 如果两个结果集的形状不同会怎样?当你调用 NextResultAsync @CharlesOkwuagwu,我添加了一个输出示例。【参考方案4】:

另一个选择是使用 James Newton-King 出色的 JSON.NET 库 - http://www.newtonsoft.com/json

下面是一个快速示例,说明如何使用它来构建集合,然后将其输出为 JSON 序列化字符串:

using Newtonsoft.Json;

class Program

    static void Main(string[] args)
    
        ArrayList objs = new ArrayList();

        //get the data reader, etc.
        while(o.Read())
        
            objs.Add(new
            
                Id = o["Id"],
                CN = o["CatName"],
                Ord = o["Ord"],
                Icon = o["Icon"]
            );
        

        //clean up datareader

        Console.WriteLine(JsonConvert.SerializeObject(objs));
        Console.ReadLine();
    

您可以通过将 SqlDataReader 的每一行读入匿名对象然后使用 JSON.NET 将其序列化为字符串来对循环执行相同操作。

希望这会有所帮助!

【讨论】:

【参考方案5】:

试试这个:

o = cmd.ExecuteReader();
var dataQuery = from d in o.Cast<DbDataRecord>()
                select new
                
                    Id = (String)d["Id"],
                    CN = (String)d["CatName"],
                    Ord = (String)d["Ord"],
                    Icon = (String)d["Icon"]
                ;
var data = dataQuery.ToArray();
JavaScriptSerializer serializer = new JavaScriptSerializer();
String jsonData = serializer.Serialize(data);

【讨论】:

我一定错过了问题上的 MVC 标签。哦,等一下,我没有,因为它不在那里...... 是的,使用 LINQ 但这也比这个函数慢。对!! @Oded:最近对 MVC 非常着迷 :)。将帖子更改为删除并在答案中添加 MVC,如果这让你开心 @Cyber​​nate - 我只是不确定return Json(...) 是否会为 OP 编译 ;) @Oded:感谢您的观察。也许用户没有在 MVC 上下文中使用它。【参考方案6】:

自 SQL Server 2016 起,Microsoft 将此功能嵌入到 sql 查询中。您可以通过在查询末尾使用FOR JSON 关键字来实现。

select * from table_example where somecolumn = somecondition FOR JSON AUTO

更多细节和例子你可以浏览这个官方文档Format JSON Output Automatically with AUTO Mode (SQL Server)

Here 是 Microsoft 的 C# 代码示例,用于从 SQL 查询中获取 JSON 字符串。

var queryWithForJson = "SELECT ... FOR JSON";
var conn = new SqlConnection("<connection string>");
var cmd = new SqlCommand(queryWithForJson, conn);
conn.Open();
var jsonResult = new StringBuilder();
var reader = cmd.ExecuteReader();
if (!reader.HasRows)

    jsonResult.Append("[]");

else

    while (reader.Read())
    
        jsonResult.Append(reader.GetValue(0).ToString());
    

警告:此解决方案仅适用于 SQL SERVER 2016 及更高版本。

【讨论】:

【参考方案7】:

我使用这个代码,基于Jonathan's answer:

private IEnumerable<Dictionary<string, object>> ConvertToDictionary(IDataReader reader)

    var columns = new List<string>();
    var rows = new List<Dictionary<string, object>>();

    for (var i = 0; i < reader.FieldCount; i++)
    
        columns.Add(reader.GetName(i));
    

    while (reader.Read())
    
        rows.Add(columns.ToDictionary(column => column, column => reader[column]));
    

    return rows;

然后:

var rows = this.ConvertToDictionary(reader);

return JsonConvert.SerializeObject(rows, Formatting.Indented);

【讨论】:

【参考方案8】:

使用Cinchoo ETL - 一个开源库,您可以通过几行代码轻松地将 SqlDataReader 导出为 JSON

string connectionstring = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Northwind;Integrated Security=True";
StringBuilder sb = new StringBuilder();

using (var conn = new SqlConnection(connectionstring))

    conn.Open();
    var comm = new SqlCommand("SELECT top 2 * FROM Customers", conn);

    using (var parser = new ChoJSONWriter(sb))
        parser.Write(comm.ExecuteReader());


Console.WriteLine(sb.ToString());

输出:

[
 
  "CustomerID": "ALFKI",
  "CompanyName": "Alfreds Futterkiste",
  "ContactName": "Maria Anders",
  "ContactTitle": "Sales Representative",
  "Address": "Obere Str. 57",
  "City": "Berlin",
  "Region": ,
  "PostalCode": "12209",
  "Country": "Germany",
  "Phone": "030-0074321",
  "Fax": "030-0076545"
 ,
 
  "CustomerID": "ANATR",
  "CompanyName": "Ana Trujillo Emparedados y helados",
  "ContactName": "Ana Trujillo",
  "ContactTitle": "Owner",
  "Address": "Avda. de la Constitución 2222",
  "City": "México D.F.",
  "Region": ,
  "PostalCode": "05021",
  "Country": "Mexico",
  "Phone": "(5) 555-4729",
  "Fax": "(5) 555-3745"
 
]

【讨论】:

【参考方案9】:

这是为了增强 Chandu 使用查询语法(从 ... 选择 ...)的 Linq 答案。如果您更喜欢方法语法,这就是您的答案。

drdr = cmd.ExecuteReader();
Record[] recs = drdr.Cast<DbDataRecord>().Select( data=>new Record
            GraphID=(drdr.IsDBNull(0) ? "" : (string)data["LabelX"])
        , XAxis=(drdr.IsDBNull(1) ? "1999-09-09 00:00:00" : Convert.ToDateTime(data["XDate"]).ToString("yyyy-MM-dd HH:mm:ss"))
        , YVal=(drdr.IsDBNull(2) ? 0 : int.Parse(data["YFreq"].ToString()))
        ).ToArray();

MemoryStream mem = new MemoryStream();
DataContractJsonSerializer szr = new DataContractJsonSerializer(typeof(Record[]));
szr.WriteObject(mem, recs);
String jsonData = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length); 

希望它对某人有所帮助。

【讨论】:

无需转换或解析,只需转换即可【参考方案10】:

这不会那么难。当我想将搜索结果以 JSON 格式返回到网页时,这就是我所做的。

首先,有一个这样的课程

public class SearchResult

    public string model_no  get; set; 
    public string result_text  get; set; 
    public string url  get; set; 
    public string image_url  get; set; 

然后有下面的代码。

        string sql_text = "select * from product_master where model_no like @search_string and active=1";
        SqlConnection connection = new SqlConnection(sql_constr);
        SqlCommand cmd = new SqlCommand(sql_text, connection);
        cmd.Parameters.AddWithValue("@search_string", "%" + search_string + "%");
        connection.Open();

        SqlDataReader rdr = cmd.ExecuteReader();

        List<SearchResult> searchresults = new List<SearchResult>();

        while (rdr.Read())
        
            SearchResult sr = new SearchResult();
            sr.model_no = rdr["model_no"].ToString();
            sr.result_text = rdr["product_name"].ToString();
            sr.url = rdr["url_key"].ToString();

            searchresults.Add(sr);

        
        connection.Close();

        //build json result
        return Json(searchresults, JsonRequestBehavior.AllowGet);

这对我很有效..

【讨论】:

【参考方案11】:

进一步Jonathan's 答案,我在 ASP.NET Core 中有类似的要求,将 SQLDataReader 的结果转换为 JSON 字符串或结果对象, 所以我为它创建了一个扩展方法:

 public static class MyExtensions
    
        public async static Task<string> toJSON(this SqlDataReader reader)
                    
            var results = await reader.GetSerialized();
            return JsonConvert.SerializeObject(results, Formatting.Indented);
        
        public async static Task<IEnumerable<Dictionary<string, object>>> GetSerialized(this SqlDataReader reader)
        
            var results = new List<Dictionary<string, object>>();
            var cols = new List<string>();
            for (var i = 0; i < reader.FieldCount; i++)
                cols.Add(reader.GetName(i));

            while (await reader.ReadAsync())
                results.Add(SerializeRow(cols, reader));

            return results;
        
        private static Dictionary<string, object> SerializeRow(IEnumerable<string> cols,
                                                        SqlDataReader reader)
        
            var result = new Dictionary<string, object>();
            foreach (var col in cols)
                result.Add(col, reader[col]);
            return result;
        
    

&按照我的要求使用它:

var result = await reader.GetSerialized(); //to get the result object

string strResult = await reader.toJSON(); //to get the result string

我创建了一个异步方法,因为在从数据库读取完成之前我还有一些其他事情要做。

【讨论】:

【参考方案12】:

我做了以下方法,它将任何 DataReader 转换为 JSON,但仅用于单深度序列化:

你应该将 reader 和列名作为字符串数组传递,例如:

String [] columns = "CustomerID", "CustomerName", "CustomerDOB";

然后调用方法

public static String json_encode(IDataReader reader, String[] columns)
    
        int length = columns.Length;

        String res = "";

        while (reader.Read())
        
            res += "";

            for (int i = 0; i < length; i++)
            
                res += "\"" + columns[i] + "\":\"" + reader[columns[i]].ToString() + "\"";

                if (i < length - 1)
                    res += ",";
            

            res += "";
        

        res += "";

        return res;
    

【讨论】:

在 c# 中,字符串是不可变的,因此基于循环的连接可能需要大量内存分配。如果您要坚持使用您概述的方法,我建议您实施一个字符串生成器。话虽如此,我个人不会尝试编写这样的 JSON 编码器。例如,如果列名或读者列值的内容包含引号、逗号或括号,输出的有效性会发生什么?【参考方案13】:

添加参考:System.Web.Extensions 到项目 那么

using System.Web.Script.Serialization;

在 c# 代码中,你可以使用 write :

 var json = new JavaScriptSerializer().Serialize(obj);

【讨论】:

以上是关于从 SqlDataReader 转换为 JSON的主要内容,如果未能解决你的问题,请参考以下文章

SqlDataReader - 如何将当前行转换为字典

将 DataTableReader 转换为 SqlDataReader

SqlDataReader将Binary列转换为bool

如何检查 SQLDataReader 项是不是为 DateTime os String 类型值?

C# - 无法将类型“IBM.Data.DB2.iSeries.iDB2DataReader”隐式转换为“System.Data.SqlClient.SqlDataReader”

在 C# 中将 SQL Datareader 转换为数据集