Read data from SqlDataReader - c#

I have a SQL Server 2008 database and I am working on it in the backend. I am working on asp.net/C#
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//how do I read strings here????
}
I know that the reader has values. My SQL command is to select just 1 column from a table. The column contains strings ONLY. I want to read the strings (rows) in the reader one by one. How do I do this?

using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var myString = rdr.GetString(0); //The 0 stands for "the 0'th column", so the first column of the result.
// Do somthing with this rows string, for example to put them in to a list
listDeclaredElsewhere.Add(myString);
}
}

string col1Value = rdr["ColumnOneName"].ToString();
or
string col1Value = rdr[0].ToString();
These are objects, so you need to either cast them or .ToString().

Put the name of the column begin returned from the database where "ColumnName" is. If it is a string, you can use .ToString(). If it is another type, you need to convert it using System.Convert.
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string column = rdr["ColumnName"].ToString();
int columnValue = Convert.ToInt32(rdr["ColumnName"]);
}

while(rdr.Read())
{
string col=rdr["colName"].ToString();
}
it wil work

Thought to share my helper method for those who can use it:
public static class Sql
{
public static T Read<T>(DbDataReader DataReader, string FieldName)
{
int FieldIndex;
try { FieldIndex = DataReader.GetOrdinal(FieldName); }
catch { return default(T); }
if (DataReader.IsDBNull(FieldIndex))
{
return default(T);
}
else
{
object readData = DataReader.GetValue(FieldIndex);
if (readData is T)
{
return (T)readData;
}
else
{
try
{
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
}
}
}
Usage:
cmd.CommandText = #"SELECT DISTINCT [SoftwareCode00], [MachineID]
FROM [CM_S01].[dbo].[INSTALLED_SOFTWARE_DATA]";
using (SqlDataReader data = cmd.ExecuteReader())
{
while (data.Read())
{
usedBy.Add(
Sql.Read<String>(data, "SoftwareCode00"),
Sql.Read<Int32>(data, "MachineID"));
}
}
The helper method casts to any value you like, if it can't cast or the database value is NULL, the result will be null.

For a single result:
if (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
For multiple results:
while (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}

I know this is kind of old but if you are reading the contents of a SqlDataReader into a class, then this will be very handy. the column names of reader and class should be same
public static List<T> Fill<T>(this SqlDataReader reader) where T : new()
{
List<T> res = new List<T>();
while (reader.Read())
{
T t = new T();
for (int inc = 0; inc < reader.FieldCount; inc++)
{
Type type = t.GetType();
string name = reader.GetName(inc);
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
if (name == prop.Name)
{
var value = reader.GetValue(inc);
if (value != DBNull.Value)
{
prop.SetValue(t, Convert.ChangeType(value, prop.PropertyType), null);
}
//prop.SetValue(t, value, null);
}
}
}
res.Add(t);
}
reader.Close();
return res;
}

I would argue against using SqlDataReader here; ADO.NET has lots of edge cases and complications, and in my experience most manually written ADO.NET code is broken in at least one way (usually subtle and contextual).
Tools exist to avoid this. For example, in the case here you want to read a column of strings. Dapper makes that completely painless:
var region = ... // some filter
var vals = connection.Query<string>(
"select Name from Table where Region=#region", // query
new { region } // parameters
).AsList();
Dapper here is dealing with all the parameterization, execution, and row processing - and a lot of other grungy details of ADO.NET. The <string> can be replaced with <SomeType> to materialize entire rows into objects.

Actually, I figured it out myself that I could do this:
while (rdr.read())
{
string str = rdr.GetValue().ToString().Trim();
}

In the simplest terms, if your query returns column_name and it holds a string:
while (rdr.Read())
{
string yourString = rdr.getString("column_name")
}

I usually read data by data reader this way. just added a small example.
string connectionString = "Data Source=DESKTOP-2EV7CF4;Initial Catalog=TestDB;User ID=sa;Password=tintin11#";
string queryString = "Select * from EMP";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
reader.Close();
}
}

You have to read database columnhere. You could have a look on following code snippet
string connectionString = ConfigurationManager.ConnectionStrings["NameOfYourSqlConnectionString"].ConnectionString;
using (var _connection = new SqlConnection(connectionString))
{
_connection.Open();
using (SqlCommand command = new SqlCommand("SELECT SomeColumnName FROM TableName", _connection))
{
SqlDataReader sqlDataReader = command.ExecuteReader();
if (sqlDataReader.HasRows)
{
while (sqlDataReader.Read())
{
string YourFirstDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
string YourSecondDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
string YourThridDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
}
}
sqlDataReader.Close();
}
_connection.Close();

I have a helper function like:
public static string GetString(object o)
{
if (o == DBNull.Value)
return "";
return o.ToString();
}
then I use it to extract the string:
tbUserName.Text = GetString(reader["UserName"]);

Related

Read all record in sql table using SqlDataReader

I want to read all records from "product" table and create objects from each records.
it only gets one records from the database, any ideas might help ?
public IReadOnlyList<Product> Search(string name)
{
var result = new List<Product>();
using (var conn = new SqlConnection(connectionString))
{
if (name == null)
{
var command = new SqlCommand("SELECT * FROM Product ", conn);
conn.Open();
using var reader = command.ExecuteReader();
{
while (reader.Read())
{
var prod = new Product((int)reader["ID"], (string)reader["Name"],
(double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
(string)reader["Description"]);
result.Add(prod);
reader.NextResult();
}
reader.Close();
conn.Close();
return result;
};
}
}
If you have several result sets, you should loop over them, i.e. you should put one more outer loop, e.g.
using var reader = command.ExecuteReader();
do {
while (reader.Read()) {
var prod = new Product(
Convert.ToInt32(reader["ID"]),
Convert.ToString(reader["Name"]),
Convert.ToDouble(reader["Price"]), // decimal will be better for money
Convert.ToInt32(reader["Stock"]),
Convert.ToInt32(reader["VATID"]),
Convert.ToString(reader["Description"])
);
result.Add(prod);
}
}
while (reader.NextResult());
Note outer do .. while loop since we always have at least one result set.
You use NextResult which advances the reader to the next result set. This makes sense if you have multiple sql queries and you'd use it after the while-loop. Here it's just unnecessary and wrong.
You are already advancing the reader to the next record with Read.
If I get rid of it, this error occur : Unable to cast object of type
'System.DBNull' to type 'System.String.
You can use IsDBNull:
int nameIndex = reader.GetOrdinal("Name");
string name = reader.IsDBNull(nameIndex) ? null : reader.GetString(nameIndex);
int descIndex = reader.GetOrdinal("Description");
string description = reader.IsDBNull(descIndex) ? null : reader.GetString(descIndex);
var prod = new Product((int)reader["ID"],
name,
(double)reader["Price"],
(int)reader["Stock"],
(int)reader["VATID"],
description);
Use it for every nullable column, for the numeric columns you could use nullable types like int?.
You have an error in your code:
Remove the line reader.NextResult();
NextResult is used for moving to next result set not next record.
Definitely remove the NextResult(). That does NOT move between individual records in the same query. Read() does this for you already. Rather, NextResult() allows you to include multiple queries in the same CommandText and run them all in one trip to the database.
Try this:
public IEnumerable<Product> Search(string name)
{
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand("SELECT * FROM Product ", conn))
{
if (!string.IsNullOrEmpty(name) )
{
command.CommandText += " WHERE Name LIKE #Name + '%'";
command.Parameters.Add("#Name", SqlDbType.NVarChar, 50).Value = name;
}
conn.Open();
using var reader = command.ExecuteReader();
{
while (reader.Read())
{
var prod = new Product((int)reader["ID"], reader["Name"].ToString(),
(double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
reader["Description"].ToString());
yield return prod;
}
}
}
}

Cannot use GetSqlValues Method from SqlDataReader c#

I make post method to select data from sql server, it works but i cant return all the data that i select and only can get one data
[HttpPost]
public Object SelectData([FromBody]DataEmployee employee)
{
DataEmployee Data = new DataEmployee();
string ConeectionString = "";
using (SqlConnection openCon = new SqlConnection(ConeectionString))
{
openCon.Open();
SqlCommand command = new SqlCommand("SELECT [ID],[FirstName] ,[LastName] ,[Gender] ,[Salary] FROM[dbo].[employeesData] WHERE[FirstName]= #zip", openCon);
command.Parameters.AddWithValue("#zip", employee.FirstName );
int result = command.ExecuteNonQuery();
SqlDataReader reader = command.ExecuteReader();
// result gives the -1 output.. but on insert its 1
if (reader.HasRows)
{
Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
reader.GetName(1));
if (reader.Read())
{
// Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
// reader.GetString(1));
}
// reader.NextResult();
// return reader.GetString(3);
}
else
{
return "Data is Empty";
}
return reader.GetString(2);
}
}
As you can see above i use getstring to return the data and that's make i only get one specified column , in here i want return all column that i get from the query, so i look all method that available from SQL Data Reader and found GetSqlValues that will fill an array of object that contains the value from for all column in the record, but i am struggling to make it works.
I already tried return reader.GetSqlValues(Data);
But it shows error message cant convert to object. Can anyone help me here i need to return all column here
You can do it like below :
string val="";
if (reader.HasRows)
{
while (reader.Read())
{
val += "ID = " + reader[0].ToString() + "; Name = " + reader[1].ToString();
}
}
else
{
return "Data is Empty";
}
reader.Close();
return val;
If you know the column name to show, then you can use it :
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}", reader["ColumnOneName"].ToString(),
reader["ColumnTwoName"].ToString());
}
To return all columns and all rows returned from the query.
int count = reader.FieldCount;
List<List<string>> data = new List<List<string>>();
while(reader.Read()) {
data.Add(Enumerable.Range(0,count -1).Select(it => reader.GetValue(it)));
}

Using IEnumerable<IDataRecord> to return data

I am trying to return data using IEnumerable with given fields, where I am calling the the method I want to reference the data with given field name and return that.
Example, here is the function
public IEnumerable<IDataRecord> GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
Calling:
IEnumerable<IDataRecord> data = bw.GetSomeData("StaffCode, Perms", "BW_Staff", "StaffCode = 'KAA'");
What must I do to return the data this way or what way ?
string staffCode = data["StaffCode"].ToString();
string perms = data["Perms"].ToString();
Thanks for any help
your data variable is a collection of rows. You need to iterate over the collection to do something interesting with each row.
foreach (var row in data)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Update:
Based on your comment that you only expect GetSomeData(...) to return a single row, I'd suggest 1 of two things.
Change the signature of GetSomeData to return an IDataRecord. and remove "yield" from the implementation.
public IDataRecord GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
return (IDataRecord)rdr;
}
}
}
}
}
Or
var row = data.FirstOrDefault();
if (row != null)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Remarks:
Your implementation of GetSomeData is incomplete. You are not even using several of the parameters, most importantly the fields parameter. And conceptually in SQL you can't parameterize which fields get returned or which table gets used (etc.), but rather you need to construct a dynamic query and execute it.
Update 2
Here is an implementation of GetSomeData that constructs a proper query (in C# 6, let me know if you need it in an earlier version).
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrWhiteSpace(where) ? "" : " WHERE " + where;
string sql = $"SELECT { string.Join(",", fields) } FROM {table} {predicate}";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
And here is how you would use it.
IEnumerable<IDataRecord> data = bw.GetSomeData(new[] { "StaffCode", "Perms" }, "BW_Staff", "StaffCode = 'KAA'");
You can either enumerate it or call .FirstOrDefault, it's your choice. Each time you call GetSomeData, it will run the query.
Update 3
GetSomeData implemented with earlier versions of C#
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrEmpty(where) ? "" : " WHERE " + where;
string sql = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", fields), table, predicate);
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}

Web Service isn't returning all the data

I was trying to create a Web Service that will connect to a SQL database and return all the links stored there.
I've written this code so far, and it only returns the last link that was inserted in the database.
I've created this method that will fetch the links:
public static string GetLinks()
{
string query = string.Format("SELECT Link FROM Linkovi");
try
{
conn.Open();
command.CommandText = query;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
query = reader["Link"].ToString();
}
reader.Close();
}
finally
{
conn.Close();
}
return query;
}
And then I just call this method here like this:
[WebMethod]
public string GetLinks()
{
return ConnectionClass.GetLinks();
}
So, if somebody can help me, I will be really grateful.
Thanks in advance!
You've declared query as string, so it gets overridden each time. Consider using stringbuilder which is efficient and append the links to it.
string query = string.Format("SELECT Link FROM Linkovi");
StringBuilder result = new StringBuilder();
try
{
conn.Open();
command.CommandText = query;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
result.Append(reader["Link"].ToString());
}
reader.Close();
}
finally
{
conn.Close();
}
return result.ToString();
You are always overwriting the result of the query.
query = reader["Link"].ToString();
Try something like the following:
// store the links in a list
var list = new List<string>();
...
while (reader.Read()) {
list.Add(reader["Link"].ToString());
}
...
// return the list of links
return list;
You're only saving the last result. Create a collection, and add the results to the collection, and join the collection values together, or change the return type of the method so that it returns the collection rather than a single string.
public static string GetLinks()
{
string query = string.Format("SELECT Link FROM Linkovi");
try
{
conn.Open();
command.CommandText = query;
List<string> links = new List<string>();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
links.Add(reader["Link"].ToString());
}
}
}
finally
{
conn.Close();
}
return string.Join(",", links); // You can change the delimiter here to something else.
}
Your GetLinks method only returns a single string. Each time through the loop, you execute:
query = reader["Link"].ToString();
So only one string is ever returned.
If you want to return all of the links, you need to build a list, and add those strings to the list. Or, perhaps, add the strings to a StringBuilder, separated by newlines or something:
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
sb.Append(reader.["Link"].ToString());
sb.Append("\n");
}
return sb.ToString();
And in your client code, you want to split them out:
string rslt = ConnectionClass.GetLinks();
string[] links = string.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);

how to retrieve values by LINQ in asp.net?

I want to set value to a literal control using LINQ. I got the result from database in var by the following code:
var result=md.StoredProc_Name(id);
Now I want to assign particular columns value to a literal. As we can do simply in asp.net as bellow with the help of datatable,
dt=obj.Test(id);
ltrlName.Text=dt.Rows[0]["Name"].ToString();
ltrlAddress.Text=dt.Rows[0]["Address"].ToString();
How can we do the same thing in LINQ?
var first = result.FirstOrDefault();
if (first != null)
{
ltrlName.Text = first.Name;
ltrlAddress.Text = first.Address;
}
Addendum - How to do this without linq to objects:
With the code below in a class called DB
var result = DB.SelectIntoItem("StoredProc_Name",
connectionString,
System.Data.CommandType.StoredProcedure,
new { param1 = "val1" });
if (!reader.Empty)
{
ltrlName.Text=result.Name;
ltrlAddress.Text=result.Address;
}
etc.
Code
public static dynamic SelectIntoItem(string SQLselect, string connectionString, CommandType cType = CommandType.Text, object parms = null)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
dynamic result = new System.Dynamic.ExpandoObject();
cmd.CommandType = cType;
cmd.CommandText = SQLselect;
if (parms != null)
Addparms(cmd, parms);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read()) // read the first one to get the columns collection
{
var cols = reader.GetSchemaTable()
.Rows
.OfType<DataRow>()
.Select(r => r["ColumnName"]);
foreach (string col in cols)
{
((IDictionary<System.String, System.Object>)result)[col] = reader[col];
}
result.Empty = false;
if (reader.Read())
{
// error, what to do?
result.Error = true;
result.ErrorMessage = "More than one row in result set.";
}
else
{
result.Error = false;
}
}
else
{
result.Empty = true;
result.Error = false;
}
}
conn.Close();
return result;
}
}
}
private static void Addparms(SqlCommand cmd, object parms)
{
// parameter objects take the form new { propname : "value", ... }
foreach (PropertyInfo prop in parms.GetType().GetProperties())
{
cmd.Parameters.AddWithValue("#" + prop.Name, prop.GetValue(parms, null));
}
}
If you are insterested follow my GitHub, I'll be making the rest of it public soon (GitHub)

Categories