Cannot use GetSqlValues Method from SqlDataReader c# - 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)));
}

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

How to get values in two indexes of a string list and assign them to two string variables C#

I'm implementing a method to return the result set that generated from the query and assign it to a string list. I have set to assign the id (id is a primary key) and name of selected db table line to index 0 and 1 in the string list. The code of that as follows,
public List<string>[] getTrafficLevel()
{
string query = "select * from traffictimeinfo where startTime<time(now()) and endTime>time(now());";
List<string>[] list = new List<string>[2];
list[0] = new List<string>();
list[1] = new List<string>();
if (this.openConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
list[0].Add(dataReader["timeslotid"] + "");
list[1].Add(dataReader["timeslotname"] + "");
}
dataReader.Close();
this.closeConnection();
return list;
}
else
{
return list;
}
}
What I want to know is how can i assign this values in two indexes into two string variables.
the method that i tried is as follows, is there anyone who knows how to implement this.. Thanks in advance..
public void predictLevel(List<String>resList)
{
string trafficTime, trafficLevel;
List<string>[]ansList = getTrafficLevel();
ansList[0] = # want to assign the string value into trafficTime string variable
ansList[1].ToString = # want to assign the string value into trafficLevel string variable
}
Have you considered using List of Tuples instead?
public List<Tuple<string,string>> getTrafficLevel()
{
string query = "select * from traffictimeinfo where startTime<time(now()) and endTime>time(now());";
List<Tuple<string,string>> list = new List<Tuple<string,string>>();
if (this.openConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
list.Add(new Tuple<string,string>(dataReader["timeslotid"] + "", dataReader["timeslotname"] + ""));
}
dataReader.Close();
this.closeConnection();
return list;
}
else
{
return list;
}
}
And your predictLevel method would be -
public void predictLevel(List<String>resList)
{
string trafficTime, trafficLevel;
List<Tuple<string,string>> ansList = getTrafficLevel();
trafficTime = ansList[0].Item1;
trafficLevel = ansList[0].Item2;
}

Why is ExecuteReader only giving me 1 row of data back?

I have this code and its only returning the first string [0] and errors on the rest of them saying the index is out of the array which means only 1 row is getting pulled BUT I DON'T KNOW WHY!!!
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = new MySqlCommand("SELECT email_address FROM account_info", connection);
MySqlDataReader reader;
try
{
connection.Open();
reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
textBox1.Text = reader[0].ToString();
textBox2.Text = reader[0].ToString();
textBox3.Text = reader[0].ToString();
}
reader.Close();
}
reader[0] accesses the first field from the reader, not the first row. Check out the sample code from MSDN.
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
This writes out the first and second columns of each row.
Also, I'm not really sure why you're not using a using statement, and why you're calling ExecuteReader in the finally block - those both look odd.
You're only getting one row because you're only calling reader.Read() once. Each time you call Read(), the reader advances to the next row and returns true; or, when the reader advances past the last row, it returns false.
The indexer returns data from additional columns, and you have only one column in your query; that's why index 1 and 2 are failing.
EDIT:
IF you're trying to loop through the reader, you need to put your three textboxes in a structure where they can be looped through as well. Simpler, but less flexible, but correct:
if (reader.HasRows)
{
reader.Read()
textBox1.Text = reader[0].ToString();
reader.Read()
textBox2.Text = reader[0].ToString();
reader.Read()
textBox3.Text = reader[0].ToString();
reader.Close();
}
more flexible:
List<TextBox> boxes = new List<TextBox> { textBox1, textBox2, textBox3 };
for (int index = 0; index < boxes.Count; index++)
{
if (!reader.Read())
{
break; // in case there are fewer rows than text boxes
}
boxes[index] = reader[0].ToString();
}
Here's the basics of what I do, replace the string EmailAddress part with whatever you need:
using (SqlConnection SQL_Conn01 = new SqlConnection(SQLSync))
{
bool IsConnected = false;
try
{
SQL_Conn01.Open();
IsConnected = true;
}
catch
{
// unable to connect
}
if (IsConnected)
{
SqlCommand GetSQL = new SqlCommand("SELECT email_address FROM account_info", SQL_Conn01);
using (SqlDataReader Reader = GetSQL.ExecuteReader())
{
while (Reader.Read())
{
string EmailAddress = Reader.GetString(0).TrimEnd();
}
}
GetSQL.Dispose();
}
}

Read data from SqlDataReader

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

What's wrong with my IF statement?

I'm creating an auditting table, and I have the easy Insert and Delete auditting methods done. I'm a bit stuck on the Update method - I need to be able to get the current values in the database, the new values in the query parameters, and compare the two so I can input the old values and changed values into a table in the database.
Here is my code:
protected void SqlDataSource1_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
string[] fields = null;
string fieldsstring = null;
string fieldID = e.Command.Parameters[5].Value.ToString();
System.Security.Principal. WindowsPrincipal p = System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
string[] namearray = p.Identity.Name.Split('\\');
string name = namearray[1];
string queryStringupdatecheck = "SELECT VAXCode, Reference, CostCentre, Department, ReportingCategory FROM NominalCode WHERE ID = #ID";
string queryString = "INSERT INTO Audit (source, action, itemID, item, userid, timestamp) VALUES (#source, #action, #itemID, #item, #userid, #timestamp)";
using (SqlConnection connection = new SqlConnection("con string = deleted for privacy"))
{
SqlCommand commandCheck = new SqlCommand(queryStringupdatecheck, connection);
commandCheck.Parameters.AddWithValue("#ID", fieldID);
connection.Open();
SqlDataReader reader = commandCheck.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount - 1; i++)
{
if (reader[i].ToString() != e.Command.Parameters[i].Value.ToString())
{
fields[i] = e.Command.Parameters[i].Value.ToString() + "Old value: " + reader[i].ToString();
}
else
{
}
}
}
fieldsstring = String.Join(",", fields);
reader.Close();
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#source", "Nominal");
command.Parameters.AddWithValue("#action", "Update");
command.Parameters.AddWithValue("#itemID", fieldID);
command.Parameters.AddWithValue("#item", fieldsstring);
command.Parameters.AddWithValue("#userid", name);
command.Parameters.AddWithValue("#timestamp", DateTime.Now);
try
{
command.ExecuteNonQuery();
}
catch (Exception x)
{
Response.Write(x);
}
finally
{
connection.Close();
}
}
}
The issue I'm having is that the fields[] array is ALWAYS null. Even though the VS debug window shows that the e.Command.Parameter.Value[i] and the reader[i] are different, the fields variable seems like it's never input into.
Thanks
You never set your fields[] to anything else than null, so it is null when you are trying to access it. You need to create the array before you can assign values to it. Try:
SqlDataReader reader = commandCheck.ExecuteReader();
fields = new string[reader.FieldCount]
I don't really understand what your doing here, but if your auditing, why don't you just insert every change into your audit table along with a timestamp?
Do fields = new string[reader.FieldCount] so that you have an array to assign to. You're trying to write to null[0].

Categories