Problem with multiple SqlDataReader and SqlCommand in a Class - c#

I have a problem with C#, I have a Class with a function for SqlDataReader and another for SqlCommand (the first one is just for read values from a DataBase and the second one is for INSERT, UPDATE, DELETE ... in the same DB).
The problem is, for the first part of the code (the login), I have to search the values from an Active Directory (it works), then I must see if the user has username and password in my own DB (it works), and then, if the user is not in the DB then I have to create it and get the ID, if it is already created then I just have to get the ID.
The problem is that I get this message :
InvalidOperationException was
unhandled by user code
There already exist an Open DataReader
associated with this Command, who as
to be closed first.
There is the code :
Class.cs :
private static string MyConnectionString = "THIS IS MY CONNECTION";
private SqlConnection MyConnection = new SqlConnection(MyConnectionString);
public SqlCommand MyCommand = new SqlCommand();
public SqlDataReader MyReader = null;
public void DBMyReader(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
MyCommand.Connection = MyConnection;
MyCommand.CommandText = SqlQuery;
MyReader = MyCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
public void DBMyUpdate(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
var cmdTest = new SqlCommand();
cmdTest.Connection = MyConnection;
cmdTest.CommandText = SqlQuery;
cmdTest.ExecuteNonQuery();
}
public void DBMyInsert(String SqlQuery)
{
DBMyUpdate(SqlQuery);
}
** Login.aspx.cs: **
MyClass.DBMyReader("SELECT util_codi,util_logi,util_nome FROM Tgep_util WHERE util_logi='"
+ Session["username"].ToString() + "'");
MyClass.MyReader.Read();
if (!MyClass.MyReader.HasRows)
{
MyClass.MyReader.Close();
MyClass.DBMyInsert("INSERT INTO Tgep_util(util_logi,util_nome) "
+ "VALUES ('" + Session["username"].ToString() + "','" + Session["nome"].ToString() + "')");
}
MyClass.DBMyReader("SELECT util_codi,util_logi,util_nome FROM Tgep_util WHERE util_logi='"
+ Session["username"].ToString() + "'");
MyClass.MyReader.Read();
Session["user_id"] = MyClass.MyReader["util_codi"].ToString();
Response.Redirect("FRM_Principal.aspx");
Edit : Update Code (Works for now)

The error means exactly what it says.. You have loaded a SQLCommand and started reading rows, and are now trying to do an insert. You need to close out that reader first, or use a new command.
in the DBMyUpdate function you could just create a new command:
public void DBMyUpdate(String SqlQuery)
{
if (MyConnection.State != ConnectionState.Open)
MyConnection.Open();
var cmdUpdate = new SqlCommand();
cmdUpdate.Connection = MyConnection;
cmdUpdate.CommandText = SqlQuery;
cmdUpdate.ExecuteNonQuery(CommandBehavior.CloseConnection);
}
edit: based on comments to this answer, it required using separate connections which seems odd/incorrect.

You can't use the same DataReader for insert/update that you used for insertion. You have to close the DataReader first before associating some other command with the DataReader.

Related

When trying to retrieve data from the database I get an error "InvalidOperationException was unhandled"

I have a form named Form1:
There is one ComboBox and one TextBox, when I select US$ from the ComboBox then it must retrieve data from the database and display 150 in the TextBox.
This is myform code:
For ComboBox;
namespace PCJ_System
{
public partial class Form1 : Form
{
SqlConnection conn;
SqlCommand cmd;
SqlDataReader dr;
public Form1()
{
InitializeComponent();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string str = "server = DESKTOP-LKEG8FM\\SQLEXPRESS;initial catalog= PCJ_DB ; Integrated Security=True;";
SqlConnection conn = new SqlConnection(str);
conn.Open();
conn = new SqlConnection(str);
string GetData = "Select [FC_Rate] from Forcur where FC_TYPE ='" + comboBox1.Text + "' ";
cmd = new SqlCommand(GetData, conn);
var returnValue = cmd.ExecuteScalar();
textBox1.Text = returnValue.ToString();
conn.Close();
}
}
}
My database table Forcur:
ID |FC_TYPE |FC_RATE|
1 US$ 150
2 UK# 210
What's wrong with my code?
This might not be the exact answer you are looking for, but you need to take care of following:
1) Assign DB connection string to SqlConnection object and open connection.
2) Since you are assigning one value to textbox, you need to use ExecuteScalar instead of ExecuteReader
Once you fix this, you should get the desired result.
Example:
conn=new SqlConnection(connectionStringHere);
conn.Open();
string GetData = "Select [FC_Rate] from Forcur where FC_TYPE ='" + comboBox1.Text + "' ";
cmd = new SqlCommand(GetData, conn);
var returnValue = cmd.ExecuteScalar();
textBox1.Text = returnValue.ToString();
conn.close();
Note: You still have SQL injection attack open in your SQL query. Try using varables instead to stop that.

C# checking if order number already exists

I've been looking into How to check user id already exists to see how to do this.
I am trying to get this working in my code, however it's not working. I don't get errors or something, but it just write data in database even if order number already exists.
The function:
private void createorderButton_Click(object sender, EventArgs e)
{
SqlConnection myConnection = dbHelper.initiallizeDB();
String query = "INSERT INTO testtabel (knaam, korder) VALUES ('" + knaamTextBox.Text + "','" + kordernrTextBox.Text + "')";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#korder";
param.Value = kordernrTextBox.Text;
cmd.Parameters.Add(param);
//sqlCommand.Connection.Open();
SqlDataReader reader = sqlCommand.ExecuteReader();
if (reader.HasRows)
{
MessageBox.Show("Order already exist");
}
else
{
reader.Close();
}
// opens execute non query
int rows_inserted = sqlCommand.ExecuteNonQuery();
if (rows_inserted > 0)
{
label2.Text = "Order has been created";
}
else
{
Console.Write("Oops! Something wrong!");
}
}
Sorry for this kinda well known and duplicated question, but for some reason I can't get it working.
You called the wrong command, change
SqlDataReader reader = sqlCommand.ExecuteReader();
to
SqlDataReader reader = cmd.ExecuteReader();
The problem is here:
SqlDataReader reader = sqlCommand.ExecuteReader();
You should execute the other command first
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
The latter command, when will be executed will tell you if there is any record in the testtabel table. If there is, then you should show the message:
Order already exist
Otherwise, you will execute your first command, that will insert the rows.
By the way, please try to avoid string concatenation, when you write sql queries. It is one of the most well known security holes. You code is open to SQL injections. You could use parameterized queries:
String query = "INSERT INTO testtabel (knaam, korder) VALUES (#knaam, #korder)";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
sqlCommand.Parameters.Add(new SqlParamete("#knaam",knaamTextBox.Text));
sqlCommand.Parameters.Add(new SqlParamete("#korder",kordernrTextBox.Text));
While your code is full of problems (magic pushbutton, SQL injections, absence of usings), there is main one. The approach you want to implement will fail on concurrent inserts, and must not be used.
Imagine, that two users run this code against the same database, using the same korder value:
1st executes SELECT - record with the given value doesn't exist;
2nd executes SELECT - record with the given value doesn't exist;
1st executes INSERT - record with the given value does exist;
2nd executes INSERT - ooops... we have a duplicate;
To avoid duplicates you must use unique indexes in database. Do not rely on your code.
You check HasRows for INSERT INTO testtabel bla...bla..bla.. not for `elect * from testtabel where korder'
Maybe you can use this (it comes from my head and not compiled, please adjust it with your own case)
private void createorderButton_Click(object sender, EventArgs e)
{
SqlConnection myConnection = dbHelper.initiallizeDB();
String query = "INSERT INTO testtabel (knaam, korder) VALUES ('" + knaamTextBox.Text + "','" + kordernrTextBox.Text + "')";
SqlCommand sqlCommand = new SqlCommand(query, myConnection);
SqlCommand cmd = new SqlCommand("select * from testtabel where korder = #korder", myConnection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#korder";
param.Value = kordernrTextBox.Text;
//sqlCommand.Connection.Open();
SqlDataReader cmdReader = sqlCommand.ExecuteReader();
if (cmdReader.HasRows)
{
MessageBox.Show("Order already exist");
}
else
{
cmdReader.Close();
}
SqlDataReader reader = sqlCommand.ExecuteReader();
// opens execute non query
int rows_inserted = sqlCommand.ExecuteNonQuery();
if (rows_inserted > 0)
{
label2.Text = "Order has been created";
}
else
{
Console.Write("Oops! Something wrong!");
}
}

Can't Update Access database File From C#.NET

I try to learn some coding with Visual C#. I create a form for add and update Access database.
I can successfully add to Access file but I can't update them.
I write a code similar below by some search in internet but I get this error:
ExecuteNonQuery requires an open and available Connection. The connection's current state is closed.
My code is:
public partial class form1 : Form
{
private OleDbConnection con;
private void btnUpDate_Click(object sender, EventArgs e)
{
string FirstName = txtFirstName.Text;
string Family = txtFamily.Text;
string City = txtCity.Text;
string approve = txtapprove.Text;
string OfficeNumber = txtOfficeNumber.Text;
string OfficialDossier = txtOfficialDossier.Text;
string Department = txtDepartment.Text;
string Organization = txtOrganization.Text;
OleDbConnection oleDBConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Data Source=F:\\Database.accdb");
string query = "UPDATE Sheet1 SET FirstName=#FirstName, Family=#Family, City=#City, approve=#approve, OfficeNumber=#OfficeNumber, OfficialDossier=#OfficialDossier, Department=#Department, Organization=#Organization WHERE OfficeNumber=#OfficeNumber";
//string query = "UPDATE aspnet_Users SET FirstName=#FirstName, Family=#Family, City=#City, approve=#approve, OfficeNumber=#OfficeNumber, OfficialDossier=#OfficialDossier, Department=#Department WHERE OfficeNumber=#OfficeNumber";
OleDbCommand cmd = new OleDbCommand(query, oleDBConn);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#OfficeNumber", OfficeNumber);
cmd.Parameters.AddWithValue("#OfficialDossier", OfficialDossier);
cmd.Parameters.AddWithValue("#FirstName", FirstName);
cmd.Parameters.AddWithValue("#Family", Family);
cmd.Parameters.AddWithValue("#City", City);
cmd.Parameters.AddWithValue("#approve", approve);
cmd.Parameters.AddWithValue("#Department", Department);
cmd.Parameters.AddWithValue("#Organization", Organization);
try
{
con.Open();
int result = cmd.ExecuteNonQuery();
if (result > 0)
MessageBox.Show("Success!");
else
MessageBox.Show("Sorry!");
}
catch (OleDbException)
{
MessageBox.Show("There is a problem!");
}
finally
{
con.Close();
}
}
}
Where I have mistake? I Don't use of DataSet and DataAdapter. Is problem from there?
I'm using VS 2010
Problem 1: You have not Opened the Connection object oleDBConn which was assigned to the OleDbCommand Object.
You have assigned oleDBConn to OleDbCommand object as below:
OleDbCommand cmd = new OleDbCommand(query, oleDBConn);//here you have assigned oleDbConn
but you have opened different ConnectionObject con as below:
con.Open();
Solution 1:
Replace This: You should always Open the OleDbConnection (oleDBConn) Object which was assigned to the OleDbCOmmand Object.
con.Open();
With This:
oleDBConn.Open();
Problem 2: You have created an Extra connection object con (on top of your btnUpDate_Click function) and by mistake you are working with the same.(Opening and closing the wrong connection object instead of proper one)
Solution 2: Remove the extra connection object created on top of btnUpDate_Click function and replace all con occurences with oleDBConn.
Complete Code:
try
{
oleDBConn.Open();
int result = cmd.ExecuteNonQuery();
if (result > 0)
MessageBox.Show("Success!");
else
MessageBox.Show("Sorry!");
}
catch (OleDbException ex)
{
MessageBox.Show("There is a problem!"+ex.ToString());
}
finally
{
oleDBConn.Close();
}

error for insert and stored data in access 2013

i have this code for insert data into access 2013
after click in the save button data insert into dataGridView and show
and when stop program and restart this,data not stored in the DB.I've done a lot of searches but can't find the solution. my class code and my button save code
class DB
{
public static OleDbConnection con = new OleDbConnection();
static DB()
{
con.ConnectionString = "Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;Persist Security Info=True";
}
public static void Insert(Person p1)
{
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES('" + p1.Name + "','" + p1.Family + "','" + p1.Telephone + "','" + p1.Major + "')";
cmd.CommandType = CommandType.Text;
cmd.CommandText = s;
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
}
}
Person p = new Person();
p.Name = txtname.Text;
p.Family = txtfamily.Text;
p.Telephone = txttell.Text;
p.Major = txtmajor.Text;
DB.Insert(p);
txttell.Text = "";
txtmajor.Text = "";
txtname.Text = "";
txtfamily.Text = "";
List<Person> people = DB.GetPeople();
dataGridView1.DataSource = people;
Choose your ACCDB file listed in your project files, select Copy To Output Directory and set its value to Never (And remember that |DataDirectory| is a substitution strings that points (for ASP.NET projects) to APP_DATA, your record is inserted in the database copied in that directory.
Said that please consider to use a parameterized query to create an sql command, not string concatenations
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES(" +
"?,?,?,?)";
cmd.CommandText = s;
cmd.Parameters.AddWithValue("#p1",p.Name);
cmd.Parameters.AddWithValue("#p2",p.Family);
cmd.Parameters.AddWithValue("#p3",p.Telephone);
cmd.Parameters.AddWithValue("#p4",p.Major);
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
Of course do not close the connection before executing the command.
Another point to change is the usage pattern of your connection. Do not create a global connection and keep it around for the lifetime of your application. Simply create and use it when needed and close/dispose immediately after
using(OleDbConnection con = new OleDbConnection("Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;" +
"Persist Security Info=True"))
{
try
{
OleDbCommand cmd = con.CreateCommand();
....
}
} // <- Here at the closing brace the connectio will be close and disposed

update a mySQL table using C#

I have written some C# to update a MySql table but I get an exception every time I call the method ExecuteNonQuery(). I have researched this on the web and every solution I find produces the same error. I have an open connection to the database and the update query to the database is written correctly. The code that I have so far come up with is :
public int executeUpdate()
{
int result = 0;
if (isConnected)
{
try
{
MySqlConnection cn = new MySqlConnection(connection.ConnectionString);
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = cn;
cmd.CommandText = "UPDATE test SET status_id = 1 WHERE test_id = 1";
int numRowsUpdated = cmd.ExecuteNonQuery();
}
catch (MySqlException exSql)
{
Console.Error.WriteLine("Error - SafeMySql: SQL Exception: " + query);
Console.Error.WriteLine(exSql.StackTrace);
}
catch (Exception ex)
{
Console.Error.WriteLine("Error - SafeMySql: Exception: " + query);
Console.Error.WriteLine(ex.StackTrace);
}
}
else
Console.Error.WriteLine("Error - SafeMySql: executeQuery failed. Not connected to DB");
}
Change your try section to the code below:
try
{
using(MySqlConnection cn = new MySqlConnection(connection.ConnectionString))
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = cn;
cmd.CommandText = "UPDATE test SET status_id = 1 WHERE test_id = 1";
cn.Open();
int numRowsUpdated = cmd.ExecuteNonQuery();
cmd.Dispose();
}
}
The connection must be opened before you execute a command. In the example above the command object will immediately be disposed and the connection object will implcitly be closed and disposed when you leave the using section.
I don't see the connection being opened.
Here is an example from MSDN: even inside a using block, they open the connection explicitly
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
Edit: The principle is the same for MySQL as it is for SQL Server:
public void CreateMySqlCommand(string myExecuteQuery, MySqlConnection myConnection)
{
MySqlCommand myCommand = new MySqlCommand(myExecuteQuery, myConnection);
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}

Categories

Resources