c# - convertir de SqlDataReader a JSON
(11)
Si quiere algo que se convierta en JSON arbitrario, puede convertirlo serializando en un diccionario (de cadena, objeto) así:
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;
}
Y luego use el objeto NewtonSoft.Json JsonConvert para obtener su JSON:
var r = Serialize(reader);
string json = JsonConvert.SerializeObject(r, Formatting.Indented);
ACTUALIZACIÓN: si solo quiere usar métodos integrados, y está utilizando MVC, puede usar el método de ayuda Json incorporado en su recién serializado:
JsonResult Index(int id) {
var r = Serialize(reader);
return Json(r, JsonRequestBehavior.AllowGet);
}
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();
}
Estoy usando aquí mi propia función para hacer serialización. Necesito saber si esta es una buena manera o debería usar otra. Por cierto, he tratado de usar JavaScriptSerializer
pero esto no funcionó con SqlDataReader. gracias
Hice el siguiente método donde convierte cualquier DataReader a JSON, pero solo para serialización de profundidad única:
debe pasar el lector y los nombres de las columnas como una matriz de cadenas, por ejemplo:
String [] columns = {"CustomerID", "CustomerName", "CustomerDOB"};
luego llama al método
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;
}
Me encuentro con casos de uso en los que el número de filas que devuelve el lector de datos puede ser problemático con respecto al consumo de memoria. El siguiente código usa un JsonWriter (de JSON.NET) sobre una secuencia. Uno puede discutir la utilidad de los enormes documentos JSON, pero a veces nuestros casos de uso son dictados por otros :-)
Algunas notas:
- My SqlDataReader puede contener varios conjuntos de resultados (''tablas'')
- Es posible que esté enviando el resultado a una secuencia de FileStream o HttpResponse
- He ''abstraído'' mis nombres de objeto para que coincidan con la primera columna devuelta por conjunto de resultados
- Debido al potencial de grandes conjuntos de resultados, utilizo métodos asincrónicos de SqlDataReader.
- Dejaré que JSON.NET maneje todo el problema de serialización de los datos reales contenidos en los resultados del lector de datos.
El código:
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();
}
Referencia:
Esto no puede ser tan difícil. Esto es lo que hice cuando quiero devolver resultados de búsqueda a una página web como JSON.
Primero, tenga una clase como esta
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; }
}
y luego tiene el código a continuación.
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);
esto me funciona muy bien ...
Esto es para mejorar la respuesta de Linq de Chandu que usa sintaxis de consulta (de ... seleccionar ...). Si prefiere la sintaxis del método, esta es su respuesta.
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);
Espero que ayude a alguien.
Prueba esto:
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);
agregar referencia: System.Web.Extensions
para proyectar luego
using System.Web.Script.Serialization;
en código c #, puede usar escribir:
var json = new JavaScriptSerializer().Serialize(obj);
Esto debería hacer el trabajo
private String sqlDatoToJson(SqlDataReader dataReader)
{
var dataTable = new DataTable();
dataTable.Load(dataReader);
string JSONString = string.Empty;
JSONString = JsonConvert.SerializeObject(dataTable);
return JSONString;
}
Además de la respuesta de Jonathan , tenía un requisito similar en ASP.NET Core para convertir el resultado de un SQLDataReader a una cadena JSON o un Objeto Result, así que creé un método de extensión para él como:
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;
}
}
y lo usé según mi requisito como:
var result = await reader.GetSerialized(); //to get the result object
o
string strResult = await reader.toJSON(); //to get the result string
Creé un método asíncrono porque tenía otras cosas que hacer hasta que la lectura finalizara desde la base de datos.
Uso este código, basado en la respuesta 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;
}
Y entonces:
var rows = this.ConvertToDictionary(reader);
return JsonConvert.SerializeObject(rows, Formatting.Indented);
Otra opción sería utilizar la excelente biblioteca JSON.NET de James Newton-King - http://www.newtonsoft.com/json
Aquí hay un ejemplo rápido sobre cómo usarlo para crear una colección y luego mostrarla como una cadena serializada 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();
}
}
Usted podría hacer lo mismo con su bucle leyendo en cada fila de su SqlDataReader en un objeto anónimo y luego usar JSON.NET para serializarlo en una cadena.
¡Espero que esto ayude!