I am trying to add code that will delete from 2 tables in access db file. Sometimes one of them will work and the other wont then when I try it another way it will do the opposite. So in the end only 1 of the 2 works.
Here is my code I hope someone can spot something I did wrong.
try
{
Conn.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = Conn;
command.CommandText = "DELETE FROM TBLNAME WHERE name =#name";
command.Parameters.AddWithValue("#name", lvlist.SelectedItems[0].Text);
command.ExecuteNonQuery();
command.CommandText = "DELETE from TBLNAME WHERE cb_listName =#listname";
command.Parameters.AddWithValue("#listname", lvlist.SelectedItems[0].Text);
command.ExecuteNonQuery();
Conn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error " + ex);
}
You should use different Command instances, one for each command you want to execute. If you do not do that then you need to clear the parameters. This is because parameters in OleDb queries are positional and not named. This means that when you add the 2nd parameter in the 2nd query the first parameter is used because it is first in the list.
using(var connection = new OleDbConnection("connection string here"))
{
connection.Open();
using(var command = new OleDbCommand("DELETE FROM TBLNAME WHERE name = #name", connection))
{
cmd.Parameters.Add(new OleDbParameter("#name", OleDbType.VarChar, 50)).Value = lvlist.SelectedItems[0].Text;
command.ExecuteNonQuery();
}
using(var command = new OleDbCommand("DELETE from TBLNAME WHERE cb_listName = #listname", connection))
{
cmd.Parameters.Add(new OleDbParameter("#listname", OleDbType.VarChar, 50)).Value = lvlist.SelectedItems[0].Text;
command.ExecuteNonQuery();
}
}
Also you should:
Use using blocks to ensure connections are closed after use. Do not try to create class scoped, or even worse global, connection instances.
You should also specify the db type for your parameters and do not use AddwithValue.
When possible also specify the length for your db types, in the above this is possible if you have a varchar type. note I toke a guess at your schema length for these columns
Finally, just a note on general best practices, do not add catch blocks that do nothing useful with the exception. At least log the type, message, and the stack trace and then repeat this recursively for each inner exception found in property InnerException. This useful information can help you figure out exactly why an exception occurred.
Use two different OleDbCommand objects.
Related
I was creating an Appointment Table and i want to check if the row contains same Date,Slot,HR exists before another user enter.
The Connection is Opened Before this shown code.
SqlCommand slot_check = new SqlCommand("select * from Appointment where AppoinmentDate='"+textBox1.Text+"' and Slot='"+comboBox3.Text+ "'and HRName='" +comboBox2.Text+"'");
SqlDataReader Exist = slot_check.ExecuteReader();
if (Exist.HasRows)
{
string message = "Appointment Already Exists!!!!!";
MessageBox.Show(message);
}
else
{
string message = "Update";
MessageBox.Show(message);
}
System.InvalidOperationException: 'ExecuteReader: Connection property has not been initialized.'
To execute a command two informations are essential:
The sql string to execute and the connection to reach the database.
Without the connection your command cannot be executed because the framework doesn't know how to read or write the database.
There is an overload for the SqlCommand constructor that takes the two required parameters:
SqlCommand cmd = new SqlCommand(sqlText, connectionInstance);
So your code should be something like this
// The command text to run, without string concatenations and with parameters placeholders
string sqlText = #"select * from Appointment
where AppoinmentDate=#aptDate
and Slot=#slot
and HRName=#name";
// Using statement to correctly close and dispose the disposable objects
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand slot_check = new SqlCommand(sqlText, cnn))
{
// A parameter for each placeholder with the proper datatype
cmd.Parameters.Add("#aptDate", SqlDbType.Date).Value = Convert.ToDateTime(textBox1.Text);
cmd.Parameters.Add("#slot", SqlDbType.NVarChar).Value = comboBox3.Text;
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = comboBox2.Text;
cnn.Open();
// Even the SqlDataReader is a disposable object
using(SqlDataReader Exist = slot_check.ExecuteReader())
{
if (Exist.HasRows)
{
string message = "Appointment Already Exists!!!!!";
MessageBox.Show(message + " " + Exist + comboBox2.Text);
}
else
{
string message = "Update";
MessageBox.Show(message);
}
}
}
As you can see the code now has a connection passed to the command constructor and a command text built without concatenating strings but using parameters.
Using parameters is a mandatory approach for any kind of database related operation. Without parameters your code could be exploited with the well known Sql Injection hack, but also, the simple presence of a single quote in your values, could break the sql syntax resulting in a Syntax Error Exception
Note that this code could still be wrong because I don't know what kind of data is stored in your table in the columns used in the WHERE statement. I assumed some kind of type but you should check against your table and verify if they are correct.
I am currently trying to implement SQL into a project with Unity3D. So far, I was able to do "normal" UPDATE, ADD, DELETE, DROP, ALTER, INSERT".
Trying to go a step further, I am trying to insert prepared statements, using this link as a guide
Here is my code :
SqlConnection sqlConnection = new SqlConnection(Connection.connectionString)
sqlConnection.Open();
SqlCommand cmd = new SqlCommand(null, sqlConnection);
cmd.CommandText = "INSERT INTO IngredientTypes (Name) VALUES (#name)";
SqlParameter nameParam = new SqlParameter("#name", SqlDbType.Text, 155);
nameParam.Value = Name;
cmd.Parameters.Add(nameParam);
cmd.Prepare();
cmd.ExecuteNonQuery();
My table looks like so :
CREATE TABLE IngredientTypes
(
IngredientTypeID INT IDENTITY(1,1) PRIMARY KEY,
Name VARCHAR(155)
);
I get this error :
SQLException : Incorrect systax near '1'.
System.Data.SqlClient.SqlConnection.ErrorHandler (System.Object sender, Mono.Data.Tds. Protocol.TdsInternalErrorMessageEventArgs e)
Help please? Thank you in advance.. I can't find where I did wrong.
You can reduce that code quite a bit with no loss of function, and even some important improvements (for example, this will close the connection even if an exception is thrown):
using (var sqlConnection = new SqlConnection(Connection.connectionString))
using (var cmd = new SqlCommand("INSERT INTO IngredientTypes (Name) VALUES (#name)", sqlConnection))
{
cmd.Parameters.Add("#name", SqlDbType.VarChar, 155).Value = Name;
sqlConnection.Open();
cmd.ExecuteNonQuery();
}
I'm not sure what's causing that exception in your existing code, though, because 1 is not used anywhere in that query. I suspect the problem has something to do with SqlDbType.Text, since that is not the correct type to use with a VarChar column, but it seems just as likely there's code somewhere we haven't seen yet that's changing your SQL command text.
Definitely the Prepare() method in your link is not needed for Sql Server. It's inherited here from DbCommand, where it's included because it's an important part of the API for some other databases, but Sql Server has handled this automatically for more than 10 years now.
SqlDbType.Text Is not the same as varchar. I don’t believe Text types have a length you specify.
Could you try below? Using the "using" structure is safer for sql connections by the way, the connection automatically closes when your process is done.
using (SqlConnection sqlConnection = new SqlConnection(Connection.connectionString))
{
SqlCommand command = new SqlCommand("INSERT INTO IngredientTypes (Name) VALUES (#name)", connection);
command.Parameters.Add("#name", SqlDbType.Varchar, 155);
command.Parameters["#name"].Value = Name; //make sure Name is string.
try
{
sqlConnection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
I tried your code exactly as it is and found no issue. Though there are few compilation errors (missing ; in line 1 and Name variable should be coming as parameter) but I am sure you know that. If you have posted your table structure and code exactly the same as you have in your project, then there is no problem in this code.
I am new to Visual C# programming language and recently i was trying to make a application that is supposed to insert into a local database of users some data but every times my code runs and the insertion works fine the database does not update.This is the code that i am using
try
{
cn.Open();
SqlCommand insert = new SqlCommand();
insert.CommandText = "insert into Clienti (Nume,Prenume,Parola,Email) values(#Nume,#Prenume,#Parola,#Email)";
insert.Connection = cn;
insert.Parameters.AddWithValue("#Nume", register_nume.Text);
insert.Parameters.AddWithValue("#Prenume", register_prenume.Text);
insert.Parameters.AddWithValue("#Parola", register_password.Text);
insert.Parameters.AddWithValue("#Email", register_email.Text);
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
MessageBox.Show("Added succesfully");
}
catch (Exception ex)
{
MessageBox.Show(""+ex);
}
I already tried the property Copy to output and it doesn't seems to work.
I am sorry for any grammar mistakes that i made,I would be grateful for any help.
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
You only need the ExecuteNonQuery, it will run the INSERT. You need to use ExecuteReader instead only when you're running a statement that produces result sets (eg. SELECT). So it should be:
insert.ExecuteNonQuery();
Its because you have to now read the database using a select statement, you cant use an INSERT SQL statement to read.
You could add the following immediately after your insert.
using(var selectCmd = new SqlCommand("SELECT Nume,Prenume,Parola,Email FROM Clienti WHERE Nume = #Nume", cn))
{
selectCmd.Parameters.AddWithValue("#Nume", register_nume.Text);
using(SqlDataReader reader = selectCmd.ExecuteReader())
{
while (reader.Read()) { }
}
}
That said if you want to know IF the row was inserted or how many records were inserted ExecuteNonQuery returns the number of rows affected. You could change that part of the code like this:
var recordsAffected = insert.ExecuteNonQuery();
if(recordsAffected > 0)
MessageBox.Show("Added succesfully");
else
MessageBox.Show("Nothing happened");
Although in this particular case it would not make sense because if nothing was inserted it would probably be caused by an Exception.
Some side notes
Always wrap types that implement IDisposable in using blocks (see code above as example). It ensures that resources are always released as soon as you are done with them even if an Exception is thrown.
Never swallow Exceptions! Either recover from one and log it or do not catch it at all. If you swallow it you will never know if/why your code broke.
This part of your code is preparing the SQL command that you are running
cn.Open();
SqlCommand insert = new SqlCommand();
insert.CommandText = "insert into Clienti (Nume,Prenume,Parola,Email) values(#Nume,#Prenume,#Parola,#Email)";
insert.Connection = cn;
insert.Parameters.AddWithValue("#Nume", register_nume.Text);
insert.Parameters.AddWithValue("#Prenume", register_prenume.Text);
insert.Parameters.AddWithValue("#Parola", register_password.Text);
insert.Parameters.AddWithValue("#Email", register_email.Text);
The SQL command that your code is running, is an INSERT statement, which only adds a new record to your table.
This statement runs the command that you setup earlier:
insert.ExecuteNonQuery();
If I understand correctly, here you are trying to read the data from the table again:
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
Problem is, your command is NOT set for reading. To read data, you need to use a SELECT statement. Something like this:
insert.CommandText = "SELECT Nume,Prenume,Parola,Email from Clienti" ;
So, to read the data after executing the insert, you should do this:
insert.CommandText = "SELECT Nume,Prenume,Parola,Email from Clienti" ;
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
You ar executing 2 times the query:
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
Try to get the affected rows
int rows = insert.ExecuteNonQuery();
I would suggest creating a stored procedure in your database and just execute the SP.
It's always better to execute SP from code and leave the SQL programming in the DB.
I am using that sqltransaction for the insert multiple tables each data.
But I have problem that have the database have the two same data.
What should I do for solve that problem?
please help me? Thanx
SqlConnection baglanti = system.baglan();
SqlCommand Trislem1_Ekle = new SqlCommand("Insert tblTr (Ad,TipID,BolgeID,Yerler,Resim) values(#Ad,#TipID,#BolgeID,#Yerler,#Resim) SELECT SCOPE_IDENTITY()", baglanti);
SqlCommand Tr2_TrAciklama = new SqlCommand("Insert tblTrAciklamaDetay (TrID,TrProgram) values((SELECT IDENT_CURRENT('tblTr')),#TrProgram)", baglanti);
Trislem1_Ekle.Parameters.AddWithValue("#Ad", txtTrAd.Text);
Trislem1_Ekle.Parameters.AddWithValue("#TipID", dlTrTip.SelectedValue);
Trislem1_Ekle.Parameters.AddWithValue("#BolgeID", BolgeID.SelectedValue);
Trislem1_Ekle.Parameters.AddWithValue("#Yerler", Yerler.Text);
Trislem1_Ekle.Parameters.AddWithValue("#Resim", Resim.SelectedValue);
Tr2_TrAciklama.Parameters.AddWithValue("#TrProgram", TrProgram.Text);
SqlTransaction sqlTrans = baglanti.BeginTransaction();
Trislem1_Ekle.Transaction = sqlTrans;
Tr2_TrAciklama.Transaction = sqlTrans;
try
{
Trislem1_Ekle.ExecuteNonQuery();
Tr2_TrAciklama.ExecuteNonQuery();
string SonIDGelen = Trislem1_Ekle.ExecuteScalar().ToString();
sqlTrans.Commit();
}
catch (Exception hata)
{
Response.Write("İşleminiz yapılamadı, Oluşan Hatanın Detayı<br />" + hata);
sqlTrans.Rollback();
}
finally
{
baglanti.Close();
baglanti.Dispose();
Trislem1_Ekle.Dispose();
Tr2_TrAciklama.Dispose();
}
As far as I see, you executing your Trislem1_Ekle command twice.
One with
Trislem1_Ekle.ExecuteNonQuery();
and the other one with;
string SonIDGelen = Trislem1_Ekle.ExecuteScalar().ToString();
Deleting the first one seems enough. Both ExecuteNonQuery and ExecuteScalar executes your query, and ExecuteScalar returns first column of the first row additionally.
Instead of disposing your database connections and commands manually, use using statement instead.
using(SqlConnection conn = new SqlConnection(conString))
{
using(SqlCommand cmd = conn.CreateCommand())
{
// Create your commands
// Add your parameter values
// Execute your commands
}
}
And don't use AddWithValue method. It may generate some unexptected results. Use .Add() method and overloads instead.
Can we stop using AddWithValue() already?
try like this
I think you are executing ExecuteScalar() twice on Command Trislem1_Ekle
Trislem1_Ekle.ExecuteNonQuery();
Tr2_TrAciklama.ExecuteNonQuery();
string SonIDGelen = Trislem1_Ekle.ExecuteScalar().ToString();
Replace with this:
string SonIDGelen = Trislem1_Ekle.ExecuteScalar().ToString();
Tr2_TrAciklama.ExecuteNonQuery();
In my testing project, I have a static class called FixtureSetup which I use to setup my integration testing data for validation.
I use the same SqlCommand and SqlParameter variable (not the object itself) within that class, repeatedly, using the same variable references over and over, assigning new SqlCommand and SqlParameter objects each time. My connection itself is created once and passed into the methods performing the setup, so each setup uses it's own distinct connection reference, and while the same conn is used multiple times, it's always in a linear sequence.
In one such method, I ran into a very odd situation, where my SqlCommand variable simply appears to have gotten tired.
cmd = new SqlCommand("INSERT INTO Subscription (User_ID, Name, Active) VALUES (#User_ID, #Name, #Active)", conn);
parameter = new SqlParameter("#User_ID", TestUserID); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Name", "TestSubscription"); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Active", true); cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("SELECT Subscription_ID FROM [Subscription] WHERE Name = 'TestSubscription'", conn);
parameter = new SqlParameter("#User_ID", TestUserID);
cmd.Parameters.Add(parameter);
using (dr = cmd.ExecuteReader())
{
while (dr.Read())
{
TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
}
}
cmd = new SqlCommand("INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (#Subscription_ID, #Company_ID)", conn);
parameter = new SqlParameter("#Subscription_ID", TestSubscriptionID); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Company_ID", KnownCompanyId); cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
In the above, at the last line shown, doing the same thing I've done quite literally in dozens of other places (insert data, read the ID column and capture it), I get the following:
SetUp : System.InvalidOperationException : ExecuteNonQuery requires an
open and available Connection. The connection's current state is
closed. at
System.Data.SqlClient.SqlConnection.GetOpenConnection(String method)
BUT - replace cmd with new variable myCmd, and everything works swimmingly!
SqlCommand myCmd;
myCmd = new SqlCommand("INSERT INTO Subscription (User_ID, Name, Active) VALUES (#User_ID, #Name, #Active)", conn);
parameter = new SqlParameter("#User_ID", TestUserID); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Name", "TestSubscription"); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Active", true); myCmd.Parameters.Add(parameter);
myCmd.ExecuteNonQuery();
myCmd = new SqlCommand("SELECT Subscription_ID FROM [Subscription] WHERE Name = 'TestSubscription'", conn);
parameter = new SqlParameter("#User_ID", TestUserID);
myCmd.Parameters.Add(parameter);
using (dr = myCmd.ExecuteReader())
{
while (dr.Read())
{
TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
}
}
myCmd = new SqlCommand("INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (#Subscription_ID, #Company_ID)", conn);
parameter = new SqlParameter("#Subscription_ID", TestSubscriptionID); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("#Company_ID", KnownCompanyId); myCmd.Parameters.Add(parameter);
myCmd.ExecuteNonQuery();
What the heck is going on here? Did my command var just get tired???
What clued me to the "fix" was I noticed in my tracing that in my "read the id" block, my cmd.Parameters block had only ONE parameter in it, the 2nd one added, and when I forced the first cmd.Parameters.Add line to execute again, the number of parameters in the list dropped to 0. That's what prompted me to try a method level SqlCommand...cause I had the crazy idea that my cmd was tired... Imagine my shock when I apparently turned out to be right!
Edit: I'm not recycling any objects here - just the variable reference itself (static SqlCommand at the class level). My apologies for the earlier confusion in my wording of the question.
use one command per query and call dispose (or better yet, wrap in a using statement). you don't want to be "reusing" ado.net components.
Big Edit:
From: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.close.aspx
You must explicitly call the Close method when you are through using
the SqlDataReader to use the associated SqlConnection for any other
purpose.
The Close method fills in the values for output parameters, return
values and RecordsAffected, increasing the time that it takes to close
a SqlDataReader that was used to process a large or complex query.
When the return values and the number of records affected by a query
are not significant, the time that it takes to close the SqlDataReader
can be reduced by calling the Cancel method of the associated
SqlCommand object before calling the Close method.
so try:
using (dr = cmd.ExecuteReader())
{
while (dr.Read())
{
TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
}
dr.Close();
}
Check that you haven't set the DataReader to CommandBehavior.CloseConnection since you mentioned that you're re-using the connection for your test initialization.
Also, the DataReader does take resources, so utilize Dispose
Do you really need to do make a new connection object after each try?
myCmd = new SqlCommand(...)
//your code
myCmd = new SqlCommand(...)
//etc
You can just say:
myCmd.CommandText = "INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (#Subscription_ID, #Company_ID)";
so that you may re-use your command object. Additionally you can reset your parameters as well after each call. Just call myCmd.Parameters.Clear().
Also, make sure you wrap your SqlCommand in a using statement so they will be properly cleaned up.
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "some proc"
cmd.Connection = conn;
//set params, get data, etc
cmd.CommandText = "another proc"
cmd.Parameters.Clear();
//set params, get date, etc.
}