конвертировать из SqlDataReader в JSON - PullRequest
30 голосов
/ 22 февраля 2011
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.спасибо

Ответы [ 13 ]

52 голосов
/ 23 апреля 2013

Если вы хотите что-то, что преобразуется в произвольный JSON, вы можете конвертировать, сериализовав это в словарь (из строки, объекта), таким образом:

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);

UPDATE: Если вы просто хотите использовать встроенные методы, и вы используете MVC, вы можете использовать встроенный вспомогательный метод Json для только что сериализованного:

JsonResult Index(int id) {
    var r = Serialize(reader);
    return Json(r, JsonRequestBehavior.AllowGet);
}
14 голосов
/ 21 января 2016

Я сталкиваюсь с случаями использования, когда количество строк, возвращаемых считывателем данных, может стать проблематичным в отношении потребления памяти.Следующий код использует JsonWriter (из JSON.NET) поверх потока.Можно, конечно, обсуждать полезность огромных документов JSON, но иногда наши варианты использования диктуются другими: -)

Несколько замечаний:

  • Мой SqlDataReader может содержать несколько наборов результатов ('tables')
  • Возможно, я отправляю вывод в поток 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("{0}Collection", 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.",
            }
        ]
    }
}

Ссылка:

14 голосов
/ 23 февраля 2011

Другой вариант - использовать превосходную библиотеку Джеймса Ньютона-Кинга 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 для сериализации его в строку.

Надеюсь, это поможет!

7 голосов
/ 04 мая 2017

Это должно сделать работу

private String sqlDatoToJson(SqlDataReader dataReader)
{
    var dataTable = new DataTable();
    dataTable.Load(dataReader);
    string JSONString = string.Empty;
    JSONString = JsonConvert.SerializeObject(dataTable);
    return JSONString;
}
7 голосов
/ 22 февраля 2011

Попробуйте это:

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);
4 голосов
/ 08 апреля 2016

Я использую этот код, основываясь на ответе Джонатана :

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);
2 голосов
/ 03 июля 2018

Начиная с SQL Server 2016, Microsoft встраивала эту функцию в SQL-запросы.Вы можете достичь этого, используя ключевое слово FOR JSON в конце ваших запросов.

select * from table_example where somecolumn = somecondition FOR JSON AUTO

для получения дополнительной информации и примера, вы можете просмотреть эти официальные документы Автоматически форматировать вывод JSON в режиме AUTO (SQLСервер)

Здесь - это пример кода C # от Microsoft для получения строки JSON из SQL-запросов.

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 и выше.

1 голос
/ 03 июля 2018

С 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"
 }
]
1 голос
/ 16 ноября 2016

В дополнение к Ответ Джонатана , у меня было похожее требование в ASP.NET Core для преобразования результата SQLDataReader в строку JSON или объект Result, поэтому я создал для него метод расширения:

 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

Я создал асинхронный метод, потому что у меня были другие вещисделано, пока чтение не было закончено из базы данных.

1 голос
/ 17 июня 2016

Это сделано для улучшения ответа Чанда на 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); 

Надеюсь, это кому-нибудь поможет.

...