ExecuteReader query with inside of it two ExecuteNonQuery - c#

I've got a problem with some queries from c# to SQL. I need to have a query executeReader and inside of it a if else that allow me to choose between two inserts queries. I'm calling a little external program(with the URL collected into the db) which allows me to choose between 1 and 2, if the 1 is chosen(pass) else(fail). I can't do that because the debug is giving me:
'A Command is yet associated with a DataReader opened, which needs to be closed.'
I don't know what to try anymore.
private void btnSTART_Click(object sender, RoutedEventArgs e)
{
sqliteCon.Open();
if (sqliteCon.State == System.Data.ConnectionState.Open)
{
string path = null;//estrazione1
SqlCommand cmd = new SqlCommand("select nomeI FROM tabL where selection=1", sqliteCon);
SqlDataReader nomeIRdr = null;//estrazione2
//qui
var scriptsToRun = new List<string>();
using (nomeIRdr = cmd.ExecuteReader())
{
while (nomeIRdr.Read())//estrazione4
{
path = nomeIRdr["nomeI"].ToString();//estrazione5
Process MyProc = Process.Start(path);//permette la run del path contenuto nel db
MyProc.WaitForExit();
var exitCode = MyProc.ExitCode;
if (exitCode == 1)
{
scriptsToRun.Add("insert into tabL resItem values 'PASS'");
}
else
{
scriptsToRun.Add("insert into tabL resItem values 'FAIL'");
}
sqliteCon.Close();
}
}
foreach (var script in scriptsToRun)
{
SqlCommand cmd1 = new SqlCommand(script, sqliteCon);
cmd1.ExecuteNonQuery();
}
}
}

Do not share single connection and cram everything into a single routine. Please, keep your code simple.
Create (and Dispose) Connection whenever you query RDBMS
Extract methods
Code:
Process execution and return execution results collection:
// Item1 - path
// Item2 - true in succeed
private List<Tuple<string, bool>> ExecuteResults() {
List<Tuple<string, bool>> result = new List<Tuple<string, bool>>();
using (var con = new SqlConnection(ConnectionStringHere)) {
con.Open();
string sql =
#"select nomeItem
from tabList
where selection = 1";
using (SqlCommand cmd = new SqlCommand(sql, con)) {
using (var reader = cmd.ExecuteReader()) {
while (reader.Read()) {
string path = Convert.ToString(reader[0]);
using (Process process = Process.Start(path)) {
process.WaitForExit();
result.Add(Tuple.Create(path, process.ExitCode == 1));
}
}
}
}
}
return result;
}
Saving results in RDBMS
private void ApplyExecuteResults(IEnumerable<Tuple<string, bool>> results) {
using (var con = new SqlConnection(ConnectionStringHere)) {
con.Open();
string sql =
#"update tabList
set resItem = #prm_resItem
where nomeItem = #prm_nomeItem";
using (SqlCommand cmd = new SqlCommand(sql, con)) {
cmd.Parameters.Add("#prm_nomeItem", SqlDbType.VarChar);
cmd.Parameters.Add("#prm_resItem", SqlDbType.VarChar);
foreach (var item in results) {
cmd.Parameters[0].Value = item.Item1;
cmd.Parameters[1].Value = item.Item2 ? "PASS" : "FAIL";
cmd.ExecuteNonQuery();
}
}
}
}
Finally, combine both routines:
private void btnSTART_Click(object sender, RoutedEventArgs e) {
ApplyExecuteResults(ExecuteResults());
}

Related

Refering to view values one by one

I have the following code which establishing an SQL connection inside of a project I am working on. What I want to do is to create a for loop which contains a method and every time the loop repeats the method runs with a different value until all views of the returned query are used.
I can't figure out how to refer to every value of the view without saving the view to a list or an array first. Any ideas?
SqlConnection Con = new SqlConnection(#"Data Source=localhost\**;Initial Catalog=ML;User Id=sa;Password='**'");
string sql = #"select product_id,Name from E_PRODUCT_PROPERTY";
var mylist = new List<WineRating>();
using (var command = new SqlCommand(sql, Con))
{
Con.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
new WineRating { product_id = reader.GetInt32(0), Name = reader.GetString(1) };
///Here goes the code I suppose
method_name(reader.GetInt32(0), reader.GetString(1));
}
}
public static int method_name(int product_id, string Name)
{
int num = x *2;
Console.WriteLine(num + Name);
}
Perhaps like this:
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
MyMethodToPrintToScreen(reader.GetInt32(0), reader.GetString(1));
}
}
With the method to print to screen
private static void MyMethodToPrintToScreen(int id, string product)
{
//Do whatever you wish with the data: example
Console.WriteLine($"My id: {id} | Product: {product}");
}
Edit
Let me make it even more obvious(using your exact code):
SqlConnection Con = new SqlConnection(#"Data Source=localhost\**;Initial Catalog=ML;User Id=sa;Password='**'");
string sql = #"select product_id,Name from E_PRODUCT_PROPERTY";
var mylist = new List<WineRating>();
using (var command = new SqlCommand(sql, Con))
{
Con.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
method_name(reader.GetInt32(0), reader.GetString(1));
}
}
}

C# - How to use ListView and SQLite database

I'm trying to add some data from a SQLite database, inside a ListView.
I'm having some difficulties as I want to insert all the data of the column and not a single record.
TEST CODE:
Form1.cs {Load}
private void home_form_Load(object sender, EventArgs e)
{
listView1.Refresh();
listView1.View = View.Details;
listView1.Columns.Add("ID");
listView1.Columns.Add("Grado");
listView1.Columns.Add("Cognome");
listView1.Columns.Add("Nome");
listView1.Columns.Add("Status");
}
Form1.cs {menu_button_gestionepax}
private void menu_button_gestionepax_Click(object sender, EventArgs e)
{
menu_button_dashboard.BackColor = System.Drawing.Color.DeepSkyBlue;
panel_dashboard.Visible = false;
gestionepersonale_panel.Visible = true;
menu_button_gestionepax.BackColor = System.Drawing.Color.Blue;
listView1.Refresh();
ListViewItem lst = new ListViewItem();
lst.SubItems.Add(LoadUsers.ManagerFind());
lst.SubItems.Add(LoadUsers.ManagerFind());
lst.SubItems.Add(LoadUsers.ManagerFind());
lst.SubItems.Add(LoadUsers.ManagerFind());
lst.SubItems.Add(LoadUsers.ManagerFind());
listView1.Items.Add(lst);
/*
string[] row = { LoadUsers.ManagerFindid(), LoadUsers.ManagerFindid() };
var listViewItem = new ListViewItem(row);
infobox_listview.Items.Add(listViewItem);
*/
}
LoadUsers.cs
public dynamic string ManagerFind()
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
var select = cnn.Query($"select id from utenti");
if (select.Any())
{ return select[0].ToString(); }
else return "wrong";
}
}
I have also done various other tests and one of the difficulties in some cases is to call string ManagerFind() from LoadUsers.cs
Try something like this to get your rows and columns from your sql i know this is how you do it in SQL im sure there is a similar way to do it with sqlLite
using (SqlConnection connection = new SqlConnection(_sqlConnectionStringFromUserImput))
{
connection.Open();
if (connection.State == ConnectionState.Open)
{
SqlCommand sqlCommand =
new SqlCommand(
"select id from utenti",
connection)
{
CommandType = CommandType.Text,
CommandTimeout = 20
};
SqlDataReader reader = sqlCommand.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
DateTime datetimefield = reader.GetFieldValue<DateTime>(0);
string stringField = reader.GetFieldValue<string>(1);
}
}
reader.Close();
}
connection.Close();
}

SQLDataReader bugging while using .Nest() or .Read()

I'm retrieving some information from an MSSQL via SQLDataReader, but while debugging it I notice in some cases the reader clears the result view with the error "Enumeration yielded no results" see the screenshot Before Running passing Read(),
After passing read()
this is my code,the error happens on getActiveUsers() method.
getDatabases() works just fine. could someone help me? cheers
public partial class automation : System.Web.UI.Page
{
SqlConnection con;
static List<ActiveUsers> activeUsers = new List<ActiveUsers>();
protected void Page_Load(object sender, EventArgs e)
{
ASPxGridView1.DataSource = activeUsers.ToList();
}
public List<ActiveUsers> getDatabases()
{
//passing query
string SqlQuery = "SELECT [WorkspaceName],[MaConfig_Customers].Name FROM [MaConfig_CustomerDatabases] INNER JOIN [MaConfig_Customers] ON [MaConfig_CustomerDatabases].CustomerId = [MaConfig_Customers].CustomerId where [MaConfig_Customers].Status = 0";
//creating connection
string sqlconn = ConfigurationManager.ConnectionStrings["MaxLiveConnectionString"].ConnectionString;
con = new System.Data.SqlClient.SqlConnection(sqlconn);
var cmd = new SqlCommand(SqlQuery, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
List<ActiveUsers> results = new List<ActiveUsers>();
if (reader.Read())
{
while (reader.Read())
{
ActiveUsers company = new ActiveUsers();
company.DatabaseName = String.Format("{0}", reader["WorkspaceName"]);
company.ClientName = String.Format("{0}", reader["Name"]);
results.Add(company);
}
}
con.Close();
return results;
}
public void getActiveUsers()
{
activeUsers.Clear();
List<ActiveUsers> Databases= getDatabases();
SqlConnection conn = new SqlConnection();
string SqlQuery = "select [disabled], [ADMN_Users1].[Record_Id] ,[ADMN_Users].[User_Id] from admn_Users1 inner join [ADMN_Users] on [ADMN_Users1].[record_Id] = [ADMN_Users].[Record_Id] Where [disabled] & 0x2 = 0 ";
for (int i = 0;i < Databases.Count;i++)
{
conn.ConnectionString =
"Data Source=MAXSQLCLUS01;" +
"Initial Catalog=" + Databases[i].ToString()+";"+
"User id=sa;" +
"Password=Max1m1zer;";
var cmd = new SqlCommand(SqlQuery, conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
int NumberOfUsersCounter = 0 ;
//TODO Select Enabled users
if (reader.Read())
{
while (reader.Read())
{
string user = String.Format("{0}", reader["User_Id"]);
//logic to remove system users
if (user.Equals("master", StringComparison.CurrentCultureIgnoreCase))
{
}
else
if (user.Equals("emailuser", StringComparison.CurrentCultureIgnoreCase))
{
}
else
if (user.Equals("webuser", StringComparison.CurrentCultureIgnoreCase))
{
}
else
{
NumberOfUsersCounter++;
}
}
ActiveUsers newEntry = new ActiveUsers();
newEntry.NumberActiveUsers = NumberOfUsersCounter.ToString();
newEntry.DatabaseName = Databases[i].DatabaseName.ToString();
newEntry.ClientName = Databases[i].ClientName.ToString();
activeUsers.Add(newEntry);
}
conn.Close();
//Add to ActiveUsers list
}
ASPxGridView1.AutoGenerateColumns = true;
ASPxGridView1.DataSource = activeUsers.ToList();
ASPxGridView1.DataBind();
}
protected void ASPxButton1_Click(object sender, EventArgs e)
{
getActiveUsers();
}
protected void btnExportExcel_Click(object sender, EventArgs e)
{
ASPxGridView1.DataBind();
ASPxGridViewExporter1.Landscape = true;
ASPxGridViewExporter1.FileName = "User Count Report";
ASPxGridViewExporter1.WriteXlsToResponse();
}
}
}
if (reader.Read())
{
while (reader.Read())
{
ActiveUsers company = new ActiveUsers();
company.DatabaseName = String.Format("{0}", reader["WorkspaceName"]);
company.ClientName = String.Format("{0}", reader["Name"]);
results.Add(company);
}
}
use this
if (reader.HasRows)
{
while (reader.Read())
{
ActiveUsers company = new ActiveUsers();
company.DatabaseName = String.Format("{0}", reader["WorkspaceName"]);
company.ClientName = String.Format("{0}", reader["Name"]);
results.Add(company);
}
}
your if Condition is wrong
if(reader.Read()) ==> is Wrong
Read() is not return boolean Value
use HasRows to check rows in SQLDataReader
You are skipping the first result. if (reader.Read()) { while(reader.Read()) {.... Remove the enclosing if, all it does is see if there is a row and retrieve it but then you do not read it, instead you do it again in the if so the first result is always discarded.
public List<ActiveUsers> getDatabases()
{
//passing query
string SqlQuery = "SELECT [WorkspaceName],[MaConfig_Customers].Name FROM [MaConfig_CustomerDatabases] INNER JOIN [MaConfig_Customers] ON [MaConfig_CustomerDatabases].CustomerId = [MaConfig_Customers].CustomerId where [MaConfig_Customers].Status = 0";
//creating connection
string sqlconn = ConfigurationManager.ConnectionStrings["MaxLiveConnectionString"].ConnectionString;
using(con = new System.Data.SqlClient.SqlConnection(sqlconn))
using(var cmd = new SqlCommand(SqlQuery, con))
{
con.Open();
using(SqlDataReader reader = cmd.ExecuteReader())
{
List<ActiveUsers> results = new List<ActiveUsers>();
while (reader.Read())
{
ActiveUsers company = new ActiveUsers();
company.DatabaseName = reader.GetString(0);
company.ClientName = reader.GetString(1);
results.Add(company);
}
}
}
return results;
}
Side notes:
company.DatabaseName = String.Format("{0}", reader["WorkspaceName"]) would be better written as company.DatabaseName = reader.GetString(0). The same goes for the next line. No need to use string.Format and you are specifying the columns and order in the query so use the ordinal index so get the native value.
I would recommend you wrap the SqlConnection and SqlDataReader in using blocks to ensure they are closed/disposed after use even in the event of an exception.

C# SqlConnection inside a loop

first time on stackoverflow.
I'm learning how to manage SqlConnection in my WebForm pages, and I want to reach the best practice to do that.
In my specific case, I have a loop and there's no way for me to run the code without errors if I don't set a new SqlConnection for every iteration of the loop (the error is about an attempt to read when reader is close).
So I declare this in the PageLoad method:
private SqlConnection con;
protected void Page_Load(object sender, EventArgs e)
{
con = new SqlConnection(connectionString);
}
Then I have this:
private int conta(int padre)
{
string SQL = "SELECT * FROM categories WHERE idp=#idpadre";
SqlCommand cd = new SqlCommand(SQL, con);
cd.Parameters.AddWithValue("#idpadre", padre);
int sub=0;
try
{
if ((con.State & ConnectionState.Open) <= 0)
{
con.Open();
}
using (SqlDataReader reader = cd.ExecuteReader())
{
while (reader.Read())
{
sub++;
}
}
}
catch (Exception err)
{
lbl.Text = "Errore conta!";
lbl.Text += err.Message;
}
finally
{
con.Close();
}
return sub;
}
protected void buildParent(int padre, int level)
{
StringBuilder sb = new StringBuilder();
sb.Append(" ");
for (int i = 0; i < level; i++)
{
sb.Append(HttpUtility.HtmlDecode(" "));
}
sb.Append("|--");
selectSQL = "SELECT * FROM categories WHERE idp=#idpadre";
SqlConnection cn = new SqlConnection(connectionString);
cmd = new SqlCommand(selectSQL, cn);
cmd.Parameters.AddWithValue("#idpadre", padre);
try
{
cn.Open();
using (SqlDataReader read = cmd.ExecuteReader())
{
while (read.Read())
{
dlParent.Items.Add(new ListItem { Text = sb.ToString() + read["cat"].ToString(), Value = read["idcat"].ToString() });
int sub = conta(Convert.ToInt32(read["idcat"]));
//int sub = 0;
if (sub > 0)
{
buildParent(Convert.ToInt32(read["idcat"]), level + 1);
}
}
read.Close();
}
}
catch (Exception err)
{
lbl.Text = "Errore buildParent!";
lbl.Text += err.Message;
}
finally
{
cn.Close();
if (s != null)
{
if (!this.IsPostBack)
{
buildPage();
buildLang();
buildImage();
}
}
}
}
In buildParent in the while loop i call "conta", but if I use the same SqlConnection (con) with both the methods I have an error about an attempt to read when reader is close.
I'm worried about the connection pool on the web server, particularly concerning the max connection reach.
So, where am I wrong? What's the best practice to manage SqlConnection?
Thank you.
You open the connection as late as possible, and you dispose as soon as possible. Let the connection pool deal with reclaiming the connections.
I usually write my code like this:
using (var conn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(commandToRun, conn))
{
cmd.Parameters.AddRange(new[]
{
new SqlParameter("myParam", "myvalue"),
new SqlParameter("myParam", "myvalue")
});
conn.Open(); // opened as late as possible
using (SqlDataReader reader = cd.ExecuteReader())
{
while (reader.Read())
{
// do stuff.
}
}
} // disposed here.
Note: To get a count from a SQL database you better use
SELECT count(*) FROM categories WHERE idp=#idpadre
And execute the query with ExecuteScalar()

How can I populate a list with values from a SQL Server database?

The list will grow and shrink depending on how many items I have in my database.
I need to populate a list not a listbox. I understand I will need to open a connection.
using (var conn = new SqlConnection(Properties.Settings.Default.DBConnectionString))
{
using (var cmd = conn.CreateCommand())
{
conn.Open();
List<string> TagList = new List<string>();
for (int i = 0; i < TagList.Count; i++)
TagList[i].Add("Data from database");
cmd.ExecuteNonQuery();
}
}
I'm really not sure how to do this and I'm sure my method up here looks very wrong so I really need help.
Could someone show me what I'm doing wrong?
public IEnumerable<string> GetTagList()
{
using (var connection = new SqlConnection(Properties.Settings.Default.DBConnectionString))
using (var cmd = connection.CreateCommand())
{
connection.Open();
cmd.CommandText = "select Tag from TagsTable"; // update select command accordingly
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return reader.GetString(reader.GetOrdinal("Tag"));
}
}
}
}
then you can call it as below
List<string> tags = GetTagList().ToList();
I would like to share my solution, hope helps someone in the future:
public List<string> getFromDataBase()
{
List<string> result = new List<string>();
using(SqlConnection con = new SqlConnection("connectionString"))
{
con.Open();
DataTable tap = new DataTable();
new SqlDataAdapter(query, con).Fill(tap);
result = tap.Rows.OfType<DataRow>().Select(dr => dr.Field<string>("columnName")).ToList();
}
return result;
}
This would do as it is (if I didn't do any typos...)
private void LoadList()
{
List<string> tagsList = new List<string>();
using (IDbConnection connection = new SqlConnection(Properties.Settings.Default.DBConnectionString))
{
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT TAGCOLUMN FROM TAGSTABLE";
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
if (!reader.IsDBNull(0))
tagsList.Add(reader.GetString(0));
}
reader.Close();
}
}
connection.Close();
}
}
EDIT:
Of course you have to change the select statement to the correct one from your database.
I just used a pseudo one to show you what to put there.

Categories