web-dev-qa-db-fra.com

convertir de SqlDataReader à JSON

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

J'utilise ici ma propre fonction pour faire de la sérialisation. J'ai besoin de savoir si c'est un bon moyen ou si je devrais en utiliser un autre. BTW J'ai essayé d'utiliser JavaScriptSerializer mais cela ne fonctionnait pas avec SqlDataReader. merci 

29
Rawhi

Si vous voulez quelque chose qui convertira en JSON arbitraire, vous pouvez le convertir en le sérialisant dans un Dictionary (Of string, object) ainsi:

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

Et utilisez ensuite l'objet NewtonSoft.Json JsonConvert pour obtenir votre JSON:

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

UPDATE: Si vous souhaitez simplement utiliser des méthodes intégrées et que vous utilisez MVC, vous pouvez utiliser la méthode d'assistance Json intégrée à votre tout récemment sérialisé:

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

Je rencontre des cas d'utilisation où le nombre de lignes renvoyées par le lecteur de données peut devenir problématique en termes de consommation de mémoire. Le code suivant utilise un JsonWriter (à partir de JSON.NET) sur un flux. On peut certes débattre de l'utilité d'énormes documents JSON, mais parfois nos cas d'utilisation sont dictés par d'autres :-)

Quelques notes:

  • Mon SqlDataReader peut contenir plusieurs ensembles de résultats ('tables')
  • J'envoie peut-être la sortie à un flux FileStream ou HttpResponse
  • J'ai "résumé" mes noms d'objet pour qu'ils correspondent à la première colonne renvoyée par jeu de résultats
  • En raison du potentiel de grands ensembles de résultats, j'utilise des méthodes asynchrones du SqlDataReader.
  • Je laisse JSON.NET gérer tout le problème de sérialisation des données réelles contenues dans les résultats du lecteur de données.

Le code:

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

Un exemple de sortie hétérogène serait:

{
    "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.",
            }
        ]
    }
}

Référence:

13
Eric Patrick

Une autre option serait d’utiliser l’excellente bibliothèque JSON.NET de James Newton-King - http://www.newtonsoft.com/json

Voici un exemple rapide sur la façon de l'utiliser pour créer une collection, puis la générer sous forme de chaîne sérialisée 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();
    }
}

Vous pouvez faire de même avec votre boucle en lisant chaque rangée de votre SqlDataReader dans un objet anonyme, puis en utilisant JSON.NET pour le sérialiser en chaîne.

J'espère que cela t'aides!

11
David Hoerster

Essaye ça:

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

Cela devrait faire le travail

private String sqlDatoToJson(SqlDataReader dataReader)
{
    var dataTable = new DataTable();
    dataTable.Load(dataReader);
    string JSONString = string.Empty;
    JSONString = JsonConvert.SerializeObject(dataTable);
    return JSONString;
}
5
gerzalez

J'utilise ce code, basé sur La réponse de Jonathan :

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

Et alors:

var rows = this.ConvertToDictionary(reader);

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

Suite à Jonathan's Answer, ASP.NET Core exigeait de convertir le résultat d'un SQLDataReader en chaîne JSON ou en objet de résultat,

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

et utilisé selon mes besoins en tant que: 

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

ou

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

J'ai créé une méthode asynchrone car j'avais d'autres tâches à faire jusqu'à ce que la lecture de la base de données soit terminée.

1
Abdul Rehman Sayed

Depuis SQL Server 2016, Microsoft a intégré cette fonctionnalité à des requêtes SQL. Vous pouvez y parvenir en utilisant le mot clé FOR JSON à la fin de vos requêtes.

select * from table_example where somecolumn = somecondition FOR JSON AUTO

pour plus de détails et un exemple, vous pouvez consulter ces documents officiels Formater automatiquement la sortie JSON avec le mode AUTO (SQL Server)

Here est l'exemple de code C # de Microsoft permettant d'obtenir une chaîne JSON à partir de requêtes 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());
    }
}

Avertissement: Cette solution n'est valable que pour SQL SERVER 2016 et versions ultérieures.

1
Muhammad Saqib

Cela améliore la réponse Linq de Chandu qui utilise la syntaxe de requête (de ... sélectionnez ...). Si vous préférez la syntaxe de méthode, voici votre réponse.

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

J'espère que ça aide quelqu'un.

1
Jenna Leaf

Cela ne peut pas être si difficile. C'est ce que j'ai fait lorsque je veux renvoyer les résultats de recherche sur une page Web au format JSON.

D'abord, avoir un cours comme celui-ci

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

et puis avoir le code ci-dessous.

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

cela fonctionne très bien pour moi ..

1
BenW

Avec Cinchoo ETL - une bibliothèque open source, vous pouvez exporter facilement SqlDataReader vers JSON avec quelques lignes de code.

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

Sortie:

[
 {
  "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"
 }
]
0
RajN

J'ai fait la méthode suivante où il convertit n'importe quel DataReader en JSON, mais uniquement pour la sérialisation à profondeur unique:

vous devez transmettre le lecteur et les noms de colonne sous forme de tableau de chaînes, par exemple:

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

puis appelez la méthode

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;
    }
0
Amjad Abu Saa

ajoutez la référence: System.Web.Extensions à project then

using System.Web.Script.Serialization;

en c # code, vous pouvez utiliser write:

 var json = new JavaScriptSerializer().Serialize(obj);
0
shiva yekta