Returning multiple sqlcommands - c#

I get that we can use using to have multiple commands in a sqlconnection.
Like this:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command1 = new SqlCommand(commandText1, connection))
{
}
using (SqlCommand command2 = new SqlCommand(commandText2, connection))
{
}
// etc
}
However, what if the using is in a method that returns a reader cast?
Like this:
public IEnumerable<LocationInfo> GetData()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ConnectionString))
{
//connection.Close();
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT .... ", connection))
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
{ connection.Open(); }
using (var reader = command.ExecuteReader())
{
return reader.Cast<IDataRecord>().Select(x => new LocationInfo()
{
Names = x.GetString(2),
Values = Math.Round(x.GetDouble(7), 2).ToString("#,##0.00"),
ValuesDouble = x.GetDouble(7),
Values2 = Math.Round(x.GetDecimal(9), 2).ToString("#,##0.00"),
ValuesDouble2 = x.GetDecimal(9),
truckDelivery=x.GetDecimal(3),
truckIdle = x.GetDecimal(4),
truckRepair = x.GetDecimal(5),
truckReady = x.GetDecimal(6),
presentEmp=x.GetInt32(11),
absentEmp = x.GetInt32(12),
ondutyEmp = x.GetInt32(13),
}).ToList();
}
/* I tried this but it just got ignored
using (var reader2 = command.ExecuteReader())
{
reader2.NextResult();
return reader2.Cast<IDataRecord>().Select(x => new LocationInfo()
{
SumVol = x.GetString(0)
}).ToList();
}*/
}
}
}
Help me please. My second using keeps getting ignored and don't assume that I know anything because I'm new to this. Thank you in advance.

You need to Read the record pointed by the SqlDataReader obtained by the ExecuteReader. Accumulate your LocationInfo in a List and return them when you have finished to loop over the reader.
public IEnumerable<LocationInfo> GetData()
{
List<LocationInfo> locations = new List<LocationInfo>();
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ConnectionString))
using (SqlCommand command = new SqlCommand(#"SELECT .... ", connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while(reader.Read())
{
LocationInfo x = new LocationInfo()
{
Names = x.GetString(2),
Values = Math.Round(x.GetDouble(7), 2).ToString("#,##0.00"),
ValuesDouble = x.GetDouble(7),
Values2 = Math.Round(x.GetDecimal(9), 2).ToString("#,##0.00"),
ValuesDouble2 = x.GetDecimal(9),
truckDelivery=x.GetDecimal(3),
truckIdle = x.GetDecimal(4),
truckRepair = x.GetDecimal(5),
truckReady = x.GetDecimal(6),
presentEmp=x.GetInt32(11),
absentEmp = x.GetInt32(12),
ondutyEmp = x.GetInt32(13),
};
locations.Add(x);
}
}
}
return locations;
}

OK so here is what you can do in your situation to merge results from two result sets into one object.
public IEnumerable<LocationInfo> GetData()
{
List<LocationInfo> locations = new List<LocationInfo>();
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ConnectionString))
using (SqlCommand command = new SqlCommand(#"SELECT .... ", connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
LocationInfo x = new LocationInfo();
while(reader.Read())
{
{
x.Names = reader.GetString(2),
x.Values=Math.Round(reader.GetDouble(7),2).ToString("#,##0.00"),
x.ValuesDouble = reader.GetDouble(7),
Values2 = Math.Round(reader.GetDecimal(9), 2).ToString("#,##0.00"),
x.ValuesDouble2 = reader.GetDecimal(9),
x.truckDelivery=reader.GetDecimal(3),
x.truckIdle = reader.GetDecimal(4),
x.truckRepair = reader.GetDecimal(5),
x.truckReady = reader.GetDecimal(6),
x.presentEmp=reader.GetInt32(11),
x.absentEmp = reader.GetInt32(12),
x.ondutyEmp = reader.GetInt32(13),
};
}
if(reader.NextResult())
{
while (reader.Read())
{
x.SumVol=reader.GetString(0);
}
}
locations.Add(x);
}
}
return locations;
}

Related

How to make an "if" based on value retrieved from Query?

I need to insert into a table "pass" or "fail", if from the query done there is a single fail instead of 'RProva' I have to put "fail" if the query can't find a single fail instead of 'RProva' I have to insert "pass", the query is working but I can't figure out how to do the if with the results of a query, maybe I have to use a "for"? Don't know. It is the attempt to make it, the second is the query where I have to insert the result of the possbile "IF"
1.
SqlCommand cmdRD = new SqlCommand("SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1");
var RD = cmdRD.ExecuteScalar();
var values = new List<string>();
using (cmdRD,sqliteCon)
{
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
2.
SqlCommand cmd1 = new SqlCommand("INSERT INTO tSD(NomeItem,ResItemDet,DateStartDet,DateEndDet) OUTPUT inserted.Id VALUES (#NI,#RProva,#DATESE,#DATEED)");
cmd1.Parameters.AddWithValue("#DATESE", DATESE);
cmd1.Parameters.AddWithValue("#DATEED", DATEED);
cmd1.Parameters.AddWithValue("#NI", NI);
using (cmd1,sqliteCon)
{
foreach (var value in values)
{
if (value.Equals(pass))
{
cmd1.Parameters.AddWithValue("#RProva", value);
}
else
{
cmd1.Parameters.AddWithValue("#RProva", fail);
}
cmd1.ExecuteNonQuery();
}
}
int generatedId = Convert.ToInt32(cmd1.ExecuteScalar());
cmd1.Parameters.Clear();
SqlCommand cmd2 = new SqlCommand("UPDATE tSE SET FK_TSD_id = #tsdId FROM tL JOIN tSE ON tL.idL = tSE.idSE WHERE tL.Selection=1 ", sqliteCon);
cmd2.Parameters.AddWithValue("#tsdId", generatedId);
cmd2.ExecuteNonQuery();
MessageBox.Show("Dato Aggiunto");
}
sqliteCon.Close();
1.1
SqlCommand cmdRD = new SqlCommand("SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1", sqliteCon);
var RD = cmdRD.ExecuteScalar();
var tot =pass;
using (cmdRD)
{
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
if(reader[0].ToString()==fail)
{
tot = fail;
break;
}
}
MessageBox.Show(tot);
}
}
i'm arrived to that(1.1) it works but i've to insert the TOT into RProva
Based on your question and comment I think you misunderstood ExecuteScalar:
ExecuteScalar executes the query, and returns the first column of the first row in the result set returned by the query. learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.executescalar
I dont know the Type of "RD" or "PASS", but the IF in your example (when using ExecuteScalar) seems OK. Else when you are using ExecuteReader you should use some kind of an loop to iterate through the Items. Like this:
string pass = "abc"; // guessing types and values
string fail = "failed";
string sqliteCon = "Data Source=(localdb)\\MSSQLLocalDB;Database=BooksDb";
using (SqlConnection connection = new SqlConnection(sqliteCon))
{
connection.Open();
var queryString = #"SELECT ResItem AS RD
FROM tSE
JOIN tL ON tSE.idSE = tL.idL
WHERE tL.Selection=1";
var values = new List<string>();
using (SqlCommand command = new SqlCommand(queryString, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
var queryInsert = #"INSERT INTO tSD (NomeItem,ResItemDet,DateStartDet,DateEndDet)
VALUES (#NI, #RProva, #DATESE, #DATEED)";
using (SqlCommand command2 = new SqlCommand(queryInsert, connection))
{
foreach(var value in values)
{
command2.Parameters.Clear();
if (value.Equals(pass))
{
command2.Parameters.AddWithValue("#RProva", value);
}
else
{
command2.Parameters.AddWithValue("#RProva", fail);
}
command2.ExecuteNonQuery();
}
}
}
Theres for sure a better way, but maybe this helps you out.
EDIT:
Here is how I would implement your code example:
using (SqlConnection sqliteCon = new SqlConnection(connection))
{
sqliteCon.Open();
var values = new List<string>();
var query = "SELECT ResItem AS RD FROM tSE JOIN tL ON tSE.idSE=tL.idL WHERE tL.Selection=1";
using (SqlCommand cmdRD = new SqlCommand(query, sqliteCon))
{
var RD = cmdRD.ExecuteScalar();
using (SqlDataReader reader = cmdRD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0].ToString());
}
}
}
int generatedId = 0;
var query2 = "INSERT INTO tSD(NomeItem,ResItemDet,DateStartDet,DateEndDet) OUTPUT inserted.Id VALUES (#NI,#RProva,#DATESE,#DATEED)";
using (SqlCommand cmd1 = new SqlCommand(query2, sqliteCon))
{
foreach (var value in values)
{
cmd1.Parameters.Clear();
cmd1.Parameters.AddWithValue("#DATESE", DATESE);
cmd1.Parameters.AddWithValue("#DATEED", DATEED);
cmd1.Parameters.AddWithValue("#NI", NI);
if (value.Equals(pass))
{
cmd1.Parameters.AddWithValue("#RProva", value);
}
else
{
cmd1.Parameters.AddWithValue("#RProva", fail);
}
cmd1.ExecuteNonQuery();
}
generatedId = Convert.ToInt32(cmd1.ExecuteScalar());
}
var query3 = "UPDATE tSE SET FK_TSD_id = #tsdId FROM tL JOIN tSE ON tL.idL = tSE.idSE WHERE tL.Selection=1 ";
using (SqlCommand cmd2 = new SqlCommand(query3, sqliteCon))
{
cmd2.Parameters.AddWithValue("#tsdId", generatedId);
cmd2.ExecuteNonQuery();
}
}

Using Prepare select statements in C#

I am having the below code where I am querying the MySQL database. I need to replace my select query to prepare statement
public static void ValidateName(List<Employees> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
for (int i = 0; i < EmpList.Count; i++)
{
selectQuery = "Select EmpName from Employee where group = #Grp AND #Name in (FirstName, LastName);";
using (MySqlConnection conn = new MySqlConnection(connStr))
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
cmd.Parameters.Add("#Grp", MySqlDbType.VarChar).Value = Grp;
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = EmpList[i].Name;
conn.Open();
var reader = cmd.ExecuteReader();
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Name doesnot exists in the DB");
}
conn.Close();
}
}
}
This code works perfectly. But for improvement I need to use the prepare statements instead of the query I am using. Because I am having similar kinds of various validation in my code, I am not sure how to reuse the parameters effectively.
You are very close. Just call cmd.Prepare(), keep references to the parameters, and reuse the command:
public static void ValidateName(List<Employees> EmpList, string Grp)
{
var connStr = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
string selectQuery;
selectQuery = "Select EmpName from Employee where group = #Grp AND #Name in (FirstName, LastName);";
using (MySqlConnection conn = new MySqlConnection(connStr)) {
conn.Open();
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
var prmGrp = cmd.Parameters.Add("#Grp", MySqlDbType.VarChar);
var prmName = cmd.Parameters.Add("#Name", MySqlDbType.VarChar);
cmd.Prepare();
for (int i = 0; i < EmpList.Count; i++)
{
prmGrp.Value = Grp;
prmName.Value = EmpList[i].Name;
using (var reader = cmd.ExecuteReader()) {
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Name doesnot exists in the DB");
}
}
}
}
conn.Close();
}
}

SQLite Database is not open Error

I have a constructor that takes data from a SQL Server database and puts it in a local SQLite database:
public ForemanController()
{
connectionString.DataSource = "dxdb02v";
connectionString.InitialCatalog = "QTRAX4619410";
connectionString.UserID = "tunnelld";
connectionString.Password = "david";
string queryString = "SELECT * FROM [QTRAXAdmin].[vwQT_Foreman]";
List<Foreman> list;
// Creates a SQL connection
using (var connection = new SqlConnection(connectionString.ToString()))
{
using (var command = new SqlCommand(queryString, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
list = new List<Foreman>();
while (reader.Read())
{
list.Add(new Foreman { ForeBadge = reader.GetString(0), ForeName = reader.GetString(1) });
}
}
}
connection.Close();
allForeman = list.ToArray();
}
string deleteSQL = "DELETE FROM Foreman;";
using (SQLiteConnection SQLconn1 = new SQLiteConnection(SQLiteConnectionString))
{
using (var command = new SQLiteCommand(deleteSQL, SQLconn1))
{
command.Connection.Open();
command.ExecuteNonQuery();
}
}
using (SQLiteConnection SQLconn2 = new SQLiteConnection(SQLiteConnectionString))
{
SQLiteCommand cmd2 = SQLconn2.CreateCommand();
foreach (Foreman row in allForeman)
{
cmd2.CommandText = "INSERT INTO Foreman (ForeBadge, ForeName) VALUES (#param1, #param2);";
cmd2.Parameters.Add(new SQLiteParameter("#param1", row.ForeBadge));
cmd2.Parameters.Add(new SQLiteParameter("#param2", row.ForeName));
cmd2.ExecuteNonQuery();
}
}
}
Everything seems to be working fine until the last using statement:
using (SQLiteConnection SQLconn2 = new SQLiteConnection(SQLiteConnectionString))
{
SQLiteCommand cmd2 = SQLconn2.CreateCommand();
foreach (Foreman row in allForeman)
{
cmd2.CommandText = "INSERT INTO Foreman (ForeBadge, ForeName) VALUES (#param1, #param2);";
cmd2.Parameters.Add(new SQLiteParameter("#param1", row.ForeBadge));
cmd2.Parameters.Add(new SQLiteParameter("#param2", row.ForeName));
cmd2.ExecuteNonQuery();
}
}
I'm getting this error:
That's because that's the only place you forgot to open the connection.
add this: SQLconn2.Open();
You forgot to open the connection.
SQLConn2.Open();

DataReader.Read() always returns false

I've been searching for hours now. I can't find anything helpful for my problem.
The Read()-function always returns false. If I run the SQL-command with sqlplus I get this result:
GERA_ID GETY_BEZEICHNUNG
---------------------------
100001 Blackberry
100002 GSM
here's a simplified version of the code:
List<Divice> divices = new List<Divice>();
using (OracleConnection connection = new OracleConnection(connectionString))
{
OracleCommand cmd = new OracleCommand("select gera_id, gety_bezeichnung from idc_geraet, idc_geraettyp where idc_geraettyp.gety_id = idc_geraet.gety_id and pers_id = 4711");
cmd.Connection = connection;
connection.Open();
OracleDataReader reader = cmd.ExecuteReader();
while(reader.Read()) //returns always false
{
Divice g = new Divice();
g.gera_id = reader.GetDecimal(0);
g.gety_bezeichnung = reader.GetString(1);
divices.Add(g);
}
reader.Close();
}
EDIT:
This Code is called before. and it works fine:
IDC_PERSON p = new IDC_PERSON();
using (OracleConnection connection = new OracleConnection(connectionString))
{
OracleCommand cmd = new OracleCommand("select PERS_VNAME, PERS_NNAME, PERS_EINTRDATUM from idc_person where PERS_ID = 4711");
cmd.Connection = connection;
connection.Open();
OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (reader.Read())
{
p.PERS_ID = user_id;
p.PERS_VNAME = reader.GetString(0);
p.PERS_NNAME = reader.GetString(1);
p.PERS_EINTRDATUM = reader.GetDateTime(2);
}
reader.Close();
}
So, here is the whole code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Oracle.DataAccess.Client;
using TelKoOpt.Models;
using System.Data;
namespace TelKoOpt.Controllers
{
public class HomeController : Controller
{
string connectionString = "user id=scott;password=tiger;" +
"data source=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)" +
"(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))";
public ActionResult Index(int user_id)
{
MyDbContext dbcontext = new MyDbContext();
IDC_PERSON p = new IDC_PERSON();
List<IDC_GERAET> geraete = new List<IDC_GERAET>();
List<TELGSMEGN> telgsmegn = new List<TELGSMEGN>();
dbcontext.pers = p;
dbcontext.geraete = geraete;
dbcontext.telgsmegn = telgsmegn;
using (OracleConnection connection = new OracleConnection(connectionString))
{
OracleCommand cmd = new OracleCommand("select PERS_VNAME, PERS_NNAME, PERS_EINTRDATUM from idc_person where PERS_ID = " + user_id);
//OracleCommand cmdTelg = new OracleCommand("select service, sum(betrag), sum(dauer), sum(anzahl), zonen from test_telgsmegn where gera_id = " + user_id + " and datumaktion between '" + "01.02.2012" + "' and '" + "20.03.2012" + "' group by service, zonen; ");
cmd.Connection = connection;
//cmdTelg.Connection = new OracleConnection(connectionString);
try
{
connection.Open();
OracleDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
p.PERS_ID = user_id;
p.PERS_VNAME = reader.GetString(0);
p.PERS_NNAME = reader.GetString(1);
p.PERS_EINTRDATUM = reader.GetDateTime(2);
}
reader.Close();
}
catch (OracleException)
{
//return View(dbcontext);
}
}
using (OracleConnection connection = new OracleConnection(connectionString))
{
OracleCommand cmd = new OracleCommand("select gera_id, gety_bezeichnung from idc_geraet, idc_geraettyp where idc_geraettyp.gety_id = idc_geraet.gety_id and pers_id = " + user_id);
cmd.Connection = connection;
try
{
connection.Open();
OracleDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
IDC_GERAET g = new IDC_GERAET();
g.gera_id = reader.GetDecimal(0);
g.gety_bezeichnung = reader.GetString(1);
geraete.Add(g);
}
reader.Close();
}
catch (OracleException)
{
//return View(dbcontext);
}
}
return View(dbcontext);
}
}
}
This may not be the answer for your case, but I ran into a similar issue when debugging code and it may help others who come across this question.
The solution I figured out was actually only specific to when you are debugging. When stepping through code, if you expand the "Results View" (which enumerates the enumerable), when you get to the part in your code that reads the data reader, the reader will already be at the end of the results, and will return false. This is because data readers are forward only, and once you've enumerated to the next result (which was done by the debugger in this case), you can't go back.
same issue faced by me this is how i fixed
use out type
public void ExecuteStoredProcReturnDataReader(string sQueryName, out IDataReader dr, List<DBParam> oParams =null)
{
try
{
dbHelper DBProvider = new dbHelper();
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
oCmd = DBProvider.CreateCommand(sQueryName, conn);
if (oParams !=null)
DBProvider.CreateParameters(oParams, ref oCmd);
dr = oCmd.ExecuteReader();
}
catch (Exception e)
{
rethrow = DataAccessExceptionHandler.HandleException(ref e);
if (rethrow)
{
throw e;
}
dr = null;
}
}

How to generate List<String> from SQL query?

If I have a DbCommand defined to execute something like:
SELECT Column1 FROM Table1
What is the best way to generate a List<String> of the returned records?
No Linq etc. as I am using VS2005.
I think this is what you're looking for.
List<String> columnData = new List<String>();
using(SqlConnection connection = new SqlConnection("conn_string"))
{
connection.Open();
string query = "SELECT Column1 FROM Table1";
using(SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
columnData.Add(reader.GetString(0));
}
}
}
}
Not tested, but this should work fine.
Loop through the Items and Add to the Collection. You can use the Add method
List<string>items=new List<string>();
using (var con= new SqlConnection("yourConnectionStringHere")
{
string qry="SELECT Column1 FROM Table1";
var cmd= new SqlCommand(qry, con);
cmd.CommandType = CommandType.Text;
con.Open();
using (SqlDataReader objReader = cmd.ExecuteReader())
{
if (objReader.HasRows)
{
while (objReader.Read())
{
//I would also check for DB.Null here before reading the value.
string item= objReader.GetString(objReader.GetOrdinal("Column1"));
items.Add(item);
}
}
}
}
Or a nested List (okay, the OP was for a single column and this is for multiple columns..):
//Base list is a list of fields, ie a data record
//Enclosing list is then a list of those records, ie the Result set
List<List<String>> ResultSet = new List<List<String>>();
using (SqlConnection connection =
new SqlConnection(connectionString))
{
// Create the Command and Parameter objects.
SqlCommand command = new SqlCommand(qString, connection);
// Create and execute the DataReader..
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount-1; i++) //The mathematical formula for reading the next fields must be <=
{
rec.Add(reader.GetString(i));
}
ResultSet.Add(rec);
}
}
If you would like to query all columns
List<Users> list_users = new List<Users>();
MySqlConnection cn = new MySqlConnection("connection");
MySqlCommand cm = new MySqlCommand("select * from users",cn);
try
{
cn.Open();
MySqlDataReader dr = cm.ExecuteReader();
while (dr.Read())
{
list_users.Add(new Users(dr));
}
}
catch { /* error */ }
finally { cn.Close(); }
The User's constructor would do all the "dr.GetString(i)"
Where the data returned is a string; you could cast to a different data type:
(from DataRow row in dataTable.Rows select row["columnName"].ToString()).ToList();
This version has the same purpose of #Dave Martin but it's cleaner, getting all column, and easy to manipulate the data if you wan't to put it on Email, View, etc.
List<string> ResultSet = new List<string>();
using (SqlConnection connection = DBUtils.GetDBConnection())
{
connection.Open();
string query = "SELECT * FROM DATABASE";
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var rec = new List<string>();
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
rec.Add(reader.GetString(i));
}
string combined = string.Join("|", rec);
ResultSet.Add(combined);
}
}
}
}

Categories

Resources