Create JsonResult from C# SqlDataReader - c#

I need to serialize a SqlDataReader to Json.
I researched some examples on the internet, however, all the results were a "text" and not an object with lines.
What am I doing wrong?
My implementation:
public JsonResult Teste()
{
using (SqlConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["Conexao"].ConnectionString))
{
db.Open();
using (SqlCommand comando = new SqlCommand("select * from USERS", db))
{
using (SqlDataReader reader = comando.ExecuteReader())
{
DataTable dataTable = new DataTable();
dataTable.Load(reader);
var resultado = JsonConvert.SerializeObject(dataTable);
return Json(resultado, JsonRequestBehavior.AllowGet);
}
}
}
}
My results:
"[{\"UsuarioID\":1,\"Email\":\"admin\",\"Nome\":\"SISTEMA\"},{\"UsuarioID\":2,\"Email\":\"marlon.tiedt#gmail.com\",\"Nome\":\"Marlon Tiedt\"},{\"UsuarioID\":3,\"Email\":\"marlon.tiedt#megasul.com.br\",\"Nome\":\"Marlon - Megasul\"}]"
Desired results:
[{"UsuarioID":1,"Email":"admin","Nome":"SISTEMA"},{"UsuarioID":2,"Email":"marlon.tiedt#gmail.com","Nome":"Marlon Tiedt"},{"UsuarioID":3,"Email":"marlon.tiedt#megasul.com.br","Nome":"Marlon - Megasul"}]

You're double-encoding the output, just pass the dataTable object to new Json(...) and it should work fine. See the modified code below
public JsonResult Teste()
{
using (SqlConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["Conexao"] .ConnectionString))
{
db.Open();
using (SqlCommand comando = new SqlCommand("select * from USERS", db))
{
using (SqlDataReader reader = comando.ExecuteReader())
{
DataTable dataTable = new DataTable();
dataTable.Load(reader);
return Json(dataTable, JsonRequestBehavior.AllowGet);
}
}
}
}

Json internally serializes whatever data you pass to it.In your case you are passing serialized string instead of actual data so it is adding slashes in the response.So remove serialization and pass object directly to Json,you will get proper json response.

-- One Standard way of doing this is convert your datatable into List<Dictionary<string, object>>. Below is the sample code.
public JsonResult Teste()
{
using (SqlConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["Conexao"].ConnectionString))
{
db.Open();
using (SqlCommand comando = new SqlCommand("select * from USERS", db))
{
using (SqlDataReader reader = comando.ExecuteReader())
{
DataTable dataTable = new DataTable();
dataTable.Load(reader);
var resultado = GetTableRows(dataTable);
return Json(resultado, JsonRequestBehavior.AllowGet);
}
}
}
}
public List<Dictionary<string, object>> GetTableRows(DataTable dtData)
{
List<Dictionary<string, object>>
lstRows = new List<Dictionary<string, object>>();
Dictionary<string, object> dictRow = null;
foreach (DataRow dr in dtData.Rows)
{
dictRow = new Dictionary<string, object>();
foreach (DataColumn col in dtData.Columns)
{
dictRow.Add(col.ColumnName, dr[col]);
}
lstRows.Add(dictRow);
}
return lstRows;
}

Related

C# - Converting DataReader to DataTable

I want to convert a DataReader to DataTable to display all customers in a list(demoClients) from the Database.
Currently I have this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MySqlConnector;
using ProjectDatabase.Controllers;
using System.Data;
using System.Data.Common;
namespace ProjectDatabase.Models
{
public class demoClientsQuery
{
public AppDb Db { get; }
public demoClientsQuery(AppDb db)
{
Db = db;
}
public async Task<demoClients> FindAllClientsAsync(int id)
{
using var cmd = Db.conDemo.CreateCommand();
cmd.CommandText = #"Query";
cmd.Parameters.Add(new MySqlParameter
{
ParameterName = "#id_customer",
DbType = DbType.Int32,
Value = id,
});
MySqlDataReader dataReader = cmd.ExecuteReader();
DataTable dataTable = new DataTable();
dataTable.Load(dataReader);
var result = await ReadAllAsync(dataTable);
return result.Count > 0 ? result[0] : null;
}
public async Task<List<demoClients>> LatestClientsAsync()
{
using var cmd = Db.conDemo.CreateCommand();
cmd.CommandText = #"Query";
var aa = await LatestClientsAsync2();
MySqlDataReader dataReader = cmd.ExecuteReader();
DataTable dataTable = new DataTable();
dataTable.Load(dataReader);
return await ReadAllAsync(dataTable);
}
public async Task<DataTable> LatestClientsAsync2()
{
using var cmd = Db.conDemo.CreateCommand();
cmd.CommandText = #"Query";
//return await ReadAllAsync(await cmd.ExecuteReaderAsync());
return await ToDataTable(cmd);
}
private async Task<DataTable> ToDataTable(MySqlCommand cmd)
{
cmd.CommandType = CommandType.Text;
using (DbDataAdapter dataAdapter = new MySqlDataAdapter(cmd))
{
cmd.CommandType = CommandType.Text;
DataTable data = new DataTable();
dataAdapter.Fill(data);
return data;
}
}
private async Task<List<demoClients>> ReadAllAsync(DataTable dataTable)
{
var adb_demo_clients = new List<demoClients>();
using (dataTable)
{
foreach (DataRow dr in dataTable.Rows)
{
int id_customer = Convert.ToInt32(dr["id_customer"]);
string delivery_person_name = Convert.ToString(dr["delivery_person_name"]);
string firstname = Convert.ToString(dr["firstname"]);
string lastname = Convert.ToString(dr["lastname"]);
string email = Convert.ToString(dr["email"]);
}
}
return adb_demo_clients;
}
}
}
The only problem I am having is that it doesn't return nothing, it returns empty, something in my code is not returning my data from my database.
Any help would be appreciated.
Thank you for your time.
You have to add item to your adb_demo_clients list, inside the foreach, on the ReadAllAsync method:
private async Task<List<demoClients>> ReadAllAsync(DataTable dataTable)
{
var adb_demo_clients = new List<demoClients>();
using (dataTable)
{
foreach (DataRow dr in dataTable.Rows)
{
demoClients d = new demoClients();
d.id_customer = Convert.ToInt32(dr["id_customer"]);
d.delivery_person_name = Convert.ToString(dr["delivery_person_name"]);
// all fields that you need
...
// Add the item in your List
adb_demo_clients.add(d);
}
}
return adb_demo_clients;
}

Not all Variables Bound Oracle REST Web API

I am getting Not all variables Bound.
Here is what My Code Looks Like.
public IEnumerable<VaultService> Get(string Branch_Desg)
{
OracleConnection con = new OracleConnection(constr);
con.Open();
DataTable dt = new DataTable();
//string sql = "select * from wemadummyvaulttable where branch_desg = " + Branch_Desg + "";
string sql = "select BRANCH_ID ,BRANCH_NAME ,BRANCHID_NUMBER ,BRANCH_ACCOUNTNO ,BRANCH_DESG ,CURRENCY ,BRANCH_BALANCE from wemadummyvaulttable where Branch_Desg =" + ":Branch_Desg";
OracleDataAdapter da = new OracleDataAdapter(sql, con);
da.Fill(dt);
List<VaultService> vr = new List<Models.VaultService>(dt.Rows.Count);
if (dt.Rows.Count > 0)
{
foreach (DataRow vaultrecord in dt.Rows)
{
vr.Add(new ReadVaultBal(vaultrecord));
}
}
return vr;
}
For some Reason its not Working like its supposed to.
Screenshot Looks Like this :
Now My Updated Code Looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WEMAVaultREST.Models;
using Oracle.ManagedDataAccess.Client;
using Oracle.ManagedDataAccess.Types;
using System.Data;
namespace WEMAVaultREST.Controllers
{
public class VaultServiceController : ApiController
{
string constr = "User ID=system; Password=admin1234; Data Source=SAM;";
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
// GET api/<controller>/5
/* public VaultService Get(string Branch_Desg)
{
OracleConnection con = new OracleConnection(constr);
con.Open();
DataTable dt = new DataTable();
string sql = "select * from wemadummyvaulttable where branch_desg = '"+Branch_Desg+"'";
OracleDataAdapter da = new OracleDataAdapter(sql,con);
da.Fill(dt);
if (dt.Rows.Count > 0)
{
return new ReadVaultBal(dt.Rows[0]);
}
throw new Exception("Account not found");
}*/
public IEnumerable<VaultService> Get(string Branch_Desg)
{
OracleConnection con = new OracleConnection(constr);
con.Open();
DataTable dt = new DataTable();
//string sql = "select * from wemadummyvaulttable where branch_desg = " + Branch_Desg + "";
string sql = "select BRANCH_ID ,BRANCH_NAME ,BRANCHID_NUMBER ,BRANCH_ACCOUNTNO ,BRANCH_DESG ,CURRENCY ,BRANCH_BALANCE from wemadummyvaulttable where Branch_Desg =" + ":Branch_Desg";
var command = new OracleCommand(sql, con);
command.Parameters.Add("Branch_Desg", Branch_Desg);
OracleDataAdapter da = new OracleDataAdapter(command);
da.Fill(dt);
List<VaultService> vr = new List<Models.VaultService>(dt.Rows.Count);
if (dt.Rows.Count > 0)
{
foreach (DataRow vaultrecord in dt.Rows)
{
vr.Add(new ReadVaultBal(vaultrecord));
}
}
return vr;
}
// POST api/<controller>
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
Thats what i have for now. As you can see it Returns in Sqldeveloper.In the Code, it does not. I do not know what and where to Go from here.
If i run the REST api just like this :
http://localhost:7177/api/VaultService?Branch_Desg=Branch01
It returns this
Try replacing the line
OracleDataAdapter da = new OracleDataAdapter(sql, con);
with
var command = new OracleCommand(sql, con);
command.Parameters.Add("Branch_Desg", branchDesg);
OracleDataAdapter da = new OracleDataAdapter(command);
It seems there isn't a way to add bind parameters directly to an OracleDataAdapter, so we have to create an OracleCommand from the SQL string first, add a value for the parameter :Branch_Desg, and then create the adapter from the command.
Finally, can I please recommend that all Oracle resources (connection, command and data-adapter) are disposed correctly, by creating them in using blocks, e.g.
using (OracleConnection con = new OracleConnection(constr))
{
// code using the database connection 'con'
}

Retrieving data from a database through SqlDataReader and converting it to JSON

I want to convert my retrieved data into JSON; I am using a SqlDataReader for retrieving. For that I need to store my data into var.
I am getting this error:
An exception of type 'System.Reflection.AmbiguousMatchException' occurred in mscorlib.dll but was not handled in user code
Additional information: Ambiguous match found.
in the following code:
public string GetDetails(int Id)
{
var jsonDoc = "";
string con = "server=FACULTY01\\SQLSERVER2012ENT; database=SampleDb; uid=sa; pwd=sa9";
SqlConnection scon = new SqlConnection(con);
string qry = "Select * from Information where ID =" + Id;
SqlCommand cmd = new SqlCommand(qry, scon);
scon.Open();
SqlDataReader rdr = cmd.ExecuteReader();
var details = rdr;
JavaScriptSerializer jss = new JavaScriptSerializer();
jsonDoc = jss.Serialize(details);
scon.Close();
return jsonDoc;
}
You can't directly serialize a SqlDataReader and expect the output to contain the data from the SQL query. That's not the way that SqlDataReader works. SqlDataReader is a means to retrieve data from the SQL result. You can use it to populate some other object (such as a Dictionary<string, object> or a strongly-typed class you define) which you can then hand to the serializer to produce JSON.
Try the code below instead. (Also note the use of using statements and parameterized SQL in keeping with good coding practices, as mentioned by #Jon Skeet.)
public static string GetDetails(int Id)
{
string con = "server=FACULTY01\\SQLSERVER2012ENT; database=SampleDb; uid=sa; pwd=sa9";
using (SqlConnection scon = new SqlConnection(con))
{
string qry = "Select * from Information where ID = #id";
SqlCommand cmd = new SqlCommand(qry, scon);
cmd.Parameters.AddWithValue("#id", Id);
scon.Open();
var details = new Dictionary<string, object>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows && rdr.Read())
{
for (int i = 0; i < rdr.FieldCount; i++)
{
details.Add(rdr.GetName(i), rdr.IsDBNull(i) ? null : rdr.GetValue(i));
}
}
}
JavaScriptSerializer jss = new JavaScriptSerializer();
string jsonDoc = jss.Serialize(details);
scon.Close();
return jsonDoc;
}
}
Note that the above code is expecting to get a single row back from the reader. If you are expecting more than one row then you will need to use another loop and put the resulting data into a List<Dictionary<string, object>> instead. Here is the part you would need to change:
...
var details = new List<Dictionary<string, object>>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
while (rdr.Read())
{
var dict = new Dictionary<string, object>();
for (int i = 0; i < rdr.FieldCount; i++)
{
dict.Add(rdr.GetName(i), rdr.IsDBNull(i) ? null : rdr.GetValue(i));
}
details.Add(dict);
}
}
}
...
You need a loop to store the data from the reader. Use a DataTable to store the full table. A single variable will store single column data.
while (rdr.Read())
{
var details = rdr["columnName"];
}
Encountered this post as it comes first in google search.
Have given an answer here (based on this):
The requirement is somewhat similar that is of converting sqldatareader result to a json string.
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;
}
}
Use As :
var result = await reader.GetSerialized(); //to get the result object
or
string strResult = await reader.toJSON(); //to get the result string

store the data coming from database in generic list

I am using generic list to store the data that comes by querying the databse.I uses List of classes actually for multiple rows.
But my problem is my classes have almost more than 20 properties and most of the time i uses only its 2 or 3 properties.
So I want to know that what is the best way to keep the data coming from database.
Below is my code
List<ImageGalleryCollection> tempList = new List<ImageGalleryCollection1>();
SqlConnection connection = Dal.GetConnection();
SqlParameter[] paramList = new SqlParameter[1];
paramList[0] = new SqlParameter("#cityId", cityId);
SqlDataReader data = Dal.ExecuteReaderSP(SPNames.GetRegCity, paramList, connection);
while(data.Read())
{
ImageGalleryCollection igc = new ImageGalleryCollection1();
igc.cityPhotoGalleryId = Convert.ToInt32(data["cityPhotoGalleryId"]);
igc.ImagePath = data["imagePath"].ToString();
tempList.Add(igc);
}
data.Close();
connection.Close();
return tempList;
In ImageGalleryCollection I have more that 20 properties and above i only uses two properties.I think it is very inefficient
Can you how your base class implementation? You can create another class with the most using attributes and use an object of that class inside your class.
IEnumerable<ImageGalleryCollection> GetImageGalleryCollection()
{
SqlConnection connection = Dal.GetConnection();
SqlParameter[] paramList = new SqlParameter[1];
paramList[0] = new SqlParameter("#cityId", cityId);
SqlDataReader data = Dal.ExecuteReaderSP(SPNames.GetRegCity, paramList,connection);
while(data.Read())
{
ImageGalleryCollection igc = new ImageGalleryCollection1();
igc.cityPhotoGalleryId = Convert.ToInt32(data["cityPhotoGalleryId"]);
igc.ImagePath = data["imagePath"].ToString();
yield return igc;
}
data.Close();
connection.Close();
}
I would like to suggest you to write a extension method for SqlDataReader and make use of the method in linq to fetch required columns from the returned rows of reader.
Extension method:
public static class DataReaderExtension
{
public static IEnumerable<Object[]> DataRecord(this System.Data.IDataReader source)
{
if (source == null)
throw new ArgumentNullException("source");
while (source.Read())
{
Object[] row = new Object[source.FieldCount];
source.GetValues(row);
yield return row;
}
}
}
using it in linq:
using (SqlConnection cn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select * from tblUser"))
{
cmd.CommandType = CommandType.Text;
cmd.Connection = cn;
cn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
var result = (from row in dr.DataRecord()
select new
{
UserId = row[0],
UserName = row[1]
}).ToList();
}
}
}
This result list has only the required properties you select and helps to reduce the consumption of memory for unwanted properties.

Loop Through Results from a Method

I have a method that calls a Proc ad returns the data. But I want to call the method and loop through all the results and use the results to plug into an Excel document. I can't seem to figure out how to loop through results coming from the method call. This is my method:
public DataView GetCoupons()
{
string connStr = ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
SqlCommand cmd = new SqlCommand("CPC_GetAllCoupons", conn);
cmd.CommandType = CommandType.StoredProcedure;
//make the dap & ds
SqlDataAdapter dap = new System.Data.SqlClient.SqlDataAdapter(cmd);
DataSet ds = new DataSet();
//open con
if (conn.State == ConnectionState.Closed)
conn.Open();
//get the data
dap.Fill(ds);
//close the conn and return
if (conn.State == ConnectionState.Open)
conn.Close();
return ds.Tables[0].DefaultView;
}
So I want to call that method and get all the results and loop through the results. How would I go about doing that?
Thanks!
When you fill a DataSet, you get a representation of all the result sets returned from the procedure call. To access individual result sets, you simply enumerate over the Tables collection like you are doing:
foreach(DataTable table in ds.Tables)
Then, you can enumerate through all the records in each dataset like so:
foreach(DataRow row in table.Rows)
And then get data from each record:
object something = row["SomeColumnName"];
DataView coupons = GetCoupons();
foreach (var row in coupons) {
// do something here
}
Something like this, should be enough
foreach (DataRowView rowView in dv) //where dv is your DataView
{
DataRow row = rowView.Row;
// Do your stuff here
}
Hope this helps.
I recommend encapsulating the data access in a repository which returns objects of a type which you require. E.g.
public class Coupon
{
public int Foo { get; set; }
public int Bar { get; set; }
}
public class CouponRepository
{
private readonly string connectionString;
public CouponRepository(string connectionString)
{
this.connectionString = connectionString;
}
public IEnumerable<Coupon> GetCoupons()
{
using(var conn = new SqlConnection(this.connectionString))
using(var cmd = new SqlCommand("CPC_GetAllCoupons", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return new Coupon
{
Foo = (int)reader["Foo"],
Bar = (int)reader["Bar"],
};
}
}
}
}
}
Usage:-
var connectionString = ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString;
var repo = new CouponRepository(connectionString);
foreach (var coupon in repo.GetCoupons())
{
// do something
}
You could use:
Dataview dv = GetCoupons();
foreach(Item item in dv.Table.Rows)
{
//...
}
But there is a lot of ways of doing this.

Categories