List<string> Assigned to Separate Array - c#

I think this is overkill but want to ask. The code below is being run, is there a need to assign the values of tempList to a totally separate array? I feel that you could iterate the values of tempList but want to verify before I make a change:
List<string> tempList = new List<string>();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
try
{
if (!reader.IsDBNull(0))
{
tempList.Add(reader[0].ToString());
}
}
catch
{
}
}
reader.Close();
crMy = tempList.ToArray();
for (int q = crMy.GetLowerBound(0); q <= crMy.GetUpperBound(0); q++)
{
return crMy[q];
}

No you don't need the array, your code could be changed to:
return tempList.First();
or FirstOrDefault depending on the code that follows.

No there is no need to initialize a new array. You can simply iterate over the List<string>.
Although you even need a List, because you are simply returning the first element in list. That will prevent you from reading every row, for example if you have 1 million entries you'll have to read them all, before returning the first one.
This code reads and directly returns the first non null value:
string result = null;
using(var reader = cmd.ExecuteReader()){
while (reader.Read()) {
if (!reader.IsDBNull(0)) {
return resultreader[0].ToString();
}
}

I believe you're correct that there's no reason to copy the List to an array in this particular context.
I would recommend using a using statement with your SqlDataReader however as it's a disposable object and I'm not seeing any dispose code here.
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
try { if (!reader.IsDBNull(0)) { tempList.Add(reader[0].ToString()); } }
catch { }
}
}

As written, your code returns the first column of the first row where that column is non-null. You could simply write this and avoid the list altogether.:
static string GetDataValue()
{
using ( SqlConnection conn = new SqlConnection("your-connect-string-here"))
using ( SqlCommand cmd = conn.CreateCommand() )
{
InitializeSqlCommand(cmd) ;
conn.Open() ;
using ( SqlDataReader reader = cmd.ExecuteReader() )
{
while ( reader.Read() && reader.IsDBNull( 0 ) )
{
string value = reader[0].ToString() ;
return value ;
}
}
}
throw new InvalidOperationException("no [useful] data returned");
}
That approach seems a little specious to me: you're returning potentially a lot of data, reading it all across the network and then throwing everything away except for the first column of the first row where that column is non-null.
You should modify the query to return just what you want, so instead something like this (rather open-ended) :
select t.col_1, t.col_2, ... , t.col_n
from foo t
change it to the more specific:
select top 1 t.col_1
from foo t
where t.col_1 is not null
Your RDBMS will thank you. Your network will thank you. Your code will run faster, your customers will be happier and and you can replace the query logic with the eminently simple and more intentional:
static string GetDataValue()
{
string value ;
using ( SqlConnection conn = new SqlConnection("your-connect-string-here"))
using ( SqlCommand cmd = conn.CreateCommand() )
{
InitializeSqlCommand(cmd) ;
conn.Open() ;
value = (string) cmd.ExecuteScalar() ;
conn.Close() ;
}
if ( value == null ) throw new InvalidOperationException("no data read") ;
return value ;
}

Related

Select SQL Server C# and Array with return [duplicate]

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

Proper use of AddWithValue in C# to Db method

Trying to do the following:
public static int GetJobStatusByNumber(int jobNumber)
{
SqlConnection connection = null;
try
{
connection = new SqlConnection(connString);
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandText = #"select STATUS from JOB
where JOB_NUMBER = #jobNumber";
cmd.Parameters.AddWithValue("#jobNumber", jobNumber);
int result = ((int)cmd.ExecuteScalar());
return result;
}
finally
{
if (connection != null)
connection.Close();
}
}
Thouht I can add the varible 'jobNumber' to the query by using 'AddWithValue' but I'm getting a cast error
Message: System.InvalidCastException : Specified cast is not valid.
What's wrong here?
Thanks.
ExecuteScalar() returns the first column of the first row in the result set returned by the query.
2 scenarios are possible:
the first column is not a int.
the query return 0 rows - in that case ExecuteScalar() will return null.
for point 1 - make sure that the first column is an int.
for point 2 - make sure you have rows. possible solution will be:
var result = 0;
var tempResult = cmd.ExecuteScalar();
if (tempResult != null) {
result = (int)tempResult;
}

SqlDataReader.HasRows return always "true" even with empty result

After browsing a multitude topics on the phenomenon of SqlDataReader.HasRows which always returns true even with empty result (and especially when it is about an SQL query with an aggregate), I dry completely on my code
However my example is very simple and HasRows returns True, FieldCount returns 1 even when there is no phpMyAdmin side line.
query = "SELECT FK_BarId FROM tlink_bar_beer WHERE FK_BeerId = " + sqlDataReader.GetInt32(0);
MySqlConnection sqlConnexionList = new MySqlConnection("server=localhost;database=beerchecking;uid=root;password=;");
MySqlCommand commandList = new MySqlCommand(query, sqlConnexionList);
sqlConnexionList.Open();
int[] BarsIds;
using (MySqlDataReader sqlDataReaderList = commandList.ExecuteReader())
{
if (sqlDataReaderList.HasRows)
{
try
{
BarsIds = new int[sqlDataReaderList.FieldCount];
int counter = 0;
if (sqlDataReaderList.Read())
{
while (sqlDataReaderList.Read())
{
int id = sqlDataReaderList.GetInt32(counter);
BarsIds[counter] = id;
counter++;
}
}
}
finally
{
sqlDataReaderList.Close();
}
}
else
{
BarsIds = new int[0];
}
}
sqlConnexionList.Close();
Do you know how to get HasRows false when there is no rows like in phpMyAdmin result?
Thanks for reading.
I prefer to use an auxiliar DataTabe instead DataReader, something like this:
DataTable dt = new DataTable();
dt.Load(commandList.ExecuteReader());
if(dt.Rows.Count > 0){
//rows exists
}else{
//no rows
}

Access Query on C# Not Generating Results

I am using the following Access query on C# MVC to compare two tables and return records that fall within the date range and machine selected by the user. The query code runs perfectly on the actual Access database but I guess something is wrong with the connection string and the code to return the results. I am not sure what's wrong with the code and I would appreciate if someone could help me determine what's wrong. Thanks!
C# MVC Controller code:
public ActionResult MissingChecksheets(string startDate, string endDate, string machine)
{
var query = $#"SELECT * FROM [TrackingLog]
WHERE [TrackingLog].[Workcenter] = '{machine}' AND
[TrackingLog].[Complete Date] > #{startDate}# AND
[TrackingLog].[Complete Date] < #{endDate}# AND
[TrackingLog].[Order Item] NOT IN (SELECT [OrderNum] FROM [dbo_Checksheet])";
var sheets = new List<Checksheet>();
using (var con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Checksheets.accdb;"))
{
using (var command = new OleDbCommand(query, con))
{
con.Open();
using (var reader = command.ExecuteReader())
{
while (reader.NextResult())
{
sheets.Add(new FabChecksheet
{
OrderNum = reader.GetString(0),
PartNum = reader.GetString(1)
});
}
}
}
}
return PartialView(sheets);
}
OleDbDataReader.NextResult() method used to move between result set if the query string has multiple result sets (e.g. more than two SELECT statements, not counting SELECT inside aggregate functions). Since your query has single result set, OleDbDataReader.Read() must be used to move between records:
using (var con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Checksheets.accdb;"))
{
using (var command = new OleDbCommand(query, con))
{
con.Open();
using (var reader = command.ExecuteReader())
{
// Only single result set, use 'Read' here
while (reader.Read())
{
sheets.Add(new FabChecksheet
{
OrderNum = reader.GetString(0),
PartNum = reader.GetString(1)
});
}
}
}
}
Note that if NextResult() is used, the data reader will move to next result set which has empty data.
Related issue:
Difference between SqlDataReader.Read and SqlDataReader.NextResult

OdbcDataReader Overwriting

I seem to be having problems with my method that will return an Integer. I am attempting to modify the rows of a particular column with this returning Integer. The database will update the pre-existing column values with this new returned value. However, it appears that every row is being modified to the LAST row's value, regardless of what the specific row held previously. I am sure my code is just overwriting the variable, but I am wondering where. Here is my method; would appreciate feedback.
private int extractValue()
{
if (connection.State != ConnectionState.Open)
{
this.connection.Open();
}
ParsingHelper helper = null // different class - no issues with this.
String query = "SELECT device FROM dLogger";
OdbcCommand command = new OdbcCommand(query, this.connection);
List<Int32> list = new List<Int32>();
OdbcDataReader reader = null;
reader = command.ExecuteReader();
while (reader.Read())
{
list.Add(reader.GetInt32(0));
for (int i = 0; i < reader.FieldCount; i++)
{
helper = new ParsingHelper();
helper.assemble(list[i]);
}
}
return helper.getFirst();
}
No problem with the ParsingHelper here, it does the correct work. My problem is the overwriting. I thought a List would alleviate this issue but I am missing something, evidently.
EDIT: Would this approach work better?
while(reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
list.Add(reader.GetInt32(i));
//....
}
If my table originally looked like this:
ColA
1
2
3
4
And my function, for example, multiplied each number by 2. The new column would look like
ColA
8 // rather than 2
8 // rather than 4
8 // rather than 6
8 // 8 is the last value - therefore, correct.
So you see, I am running into some overwriting issues here. It appears the reader will read effectively and to the last row but it is not modifying values correctly, it is only assigning each value to the last value.
EDIT:
Here is where I am updating my database:
private void update()
{
String query = "UPDATE dLogger SET device = ?";
OdbcCommand command = new OdbcCommand(query, this.connection);
if (this.connection.State != ConnectionState.Open)
{
this.connection.Open();
}
command.Parameters.AddWithValue("?", extractValue());
}
Also, here is my simple Parsing Helper Class assemble()
private void assemble(int value)
{
setFirst(value);
}
private void setFirst(int value)
{
value = value * 2;
}
Just change your
String query = "SELECT device FROM dLogger";
to
String query = "UPDATE dLogger SET device=device*2";
thus:
private void extractValue()
{
if (connection.State != ConnectionState.Open)
{
this.connection.Open();
}
String query = "UPDATE dLogger SET device=device*2";
OdbcCommand command = new OdbcCommand(query, this.connection);
command.Execute();
}

Categories

Resources