sqltransaction insert a double record while insert data - c#

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();

Related

Check if a row exists using windows form?

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.

How to retrieve data from SQL Server in C# using ADO.NET?

Would you please show me how to retrieve data from SQL Server to C# (Windows Forms application)?
Consider I have a textbox and I need to fill it with data from SQL Server WHERE 'emp_id = something' for example, how can I do it without a DataGridView?
Or take this another example:
SELECT sum(column) FROM table_name
How to get the value of the above command (also without a DataGridView)?
There are multiple ways to achieve this. You can use DataReader or DataSet \ DataTable. These are connected and disconnected architectures respectively. You can also use ExecuteScalar if you want to retrieve just one value.
Recommendations:
Enclose SqlConnection (and any other IDisposable object) in using block. My code uses try-catch block.
Always use parameterized queries.
Following is some example code with DataReader in case your query returns multiple rows. The code is copied from here.
//Declare the SqlDataReader
SqlDataReader rdr = null;
//Create connection
SqlConnection conn = new SqlConnection("Your connection string");
//Create command
SqlCommand cmd = new SqlCommand("Your sql statement", conn);
try
{
//Open the connection
conn.Open();
// 1. get an instance of the SqlDataReader
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
// get the results of each column
string field1 = (string)rdr["YourField1"];
string field2 = (string)rdr["YourField2"];
}
}
finally
{
// 3. close the reader
if(rdr != null)
{
rdr.Close();
}
// close the connection
if(conn != null)
{
conn.Close();
}
}
In case your query returns single value, you can continue with above code except SqlDataReader. Use int count = cmd.ExecuteScalar();. Please note that ExecuteScalar may return null; so you should take additional precautions.
Filling a Textbox:
using (var sqlConnection = new SqlConnection("your_connectionstring"))
{
sqlConnection.Open();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "select sum(field) from your_table";
object result = sqlCommand.ExecuteScalar();
textBox1.Text = result == null ? "0" : result.ToString();
}
sqlConnection.Close();
}
for reading more than one row you can take a look at SqlCommand.ExecuteReader()
You need to use direct database access such as in the System.Data.SqlClient Namespace which is documented here System.Data.SqlClient Namespace.
Basically, look up creating a SQLConnection and SQLCommand and using them to retrieve the data.

C# MS SQL Update statement not updating database

I have a local MS SQL Database, and I want to update one of it's bit field.
I have the following code:
static void UpgradeVevo(string nev)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("UPDATE Vevok SET Torzsvendeg=True Where Nev=" + nev, connection);
command.ExecuteNonQuery();
}
Console.WriteLine(nev+" mostmár törzsvendég");
}
Torzsvendeg is a bit datatype(I have tried to set its value to 1 too), and Nev is varchar.
The connectionstring should be fine, since I have tried Select in another method and it works fine. The above code throws no exceptions, but the table does not get updated.
I have tried to find an answer for quite some time, with no success :/. Thank you for your help in advance!
True should be in a single quote since it's a string literal like
UPDATE Vevok SET Torzsvendeg='True'
Well brother, you are messed up with quotes. Your query should look like
"UPDATE Vevok SET Torzsvendeg = 1 Where Nev = '" + nev + "'"
Again, use parametarized query and not this concatenated one to avoid SQL Injection
If the column is a boolean (bit in sql server) then you will have to write
Torzsvendeg=1
instead of
Torzsvendeg='True'
or
Torzsvendeg=True
Edit:
Please try this:
static void UpgradeVevo(string nev)
{
var connection = new SqlConnection(connectionString))
connection.Open(); // try doing this without a using
SqlCommand command = new SqlCommand("UPDATE Vevok SET Torzsvendeg=#enabled Where Nev=#nev", connection);
command.Parameters.AddWithValue(#"enabled", 1);
command.Parameters.AddWithValue(#"nev", "vevo123");
command.ExecuteNonQuery();
command.Parameters.Clear(); // always clear after executed
// close connection when you shut down your application
connection.Close();
connection.Dispose();
Console.WriteLine(nev+" mostmár törzsvendég");
}

Getting column information in SQL

I am somwhat new to SQL, so I am not sure I am going about this the right way.
I am trying to fetch data from my SQL Server database where I want to find out if checkedin is 1/0, but it needs to search on a specific user and sort after the newest date as well.
What I am trying to do is something like this:
string connectionString = ".....";
SqlConnection cnn = new SqlConnection(connectionString);
SqlCommand checkForInOrOut = new SqlCommand("SELECT CHECKEDIN from timereg ORDER BY TIME DESC LIMIT 1 WHERE UNILOGIN = '" + publiclasses.unilogin + "'", cnn);
So my question, am I doing this right? And how do I fetch the data collected, if everything was handled correctly it should return 1 or 0. Should I use some sort of SqlDataReader? I am doing this in C#/WPF
Thanks
using (SqlDataReader myReader = checkForInOrOut.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
This is how you would read data from SQL, but i recommend you looking into Parameters.AddWithValue
There are some errors in your query. First WHERE goes before ORDER BY and LIMIT is an MySql keyword while you are using the Sql Server classes. So you should use TOP value instead.
int checkedIn = 0;
string cmdText = #"SELECT TOP 1 CHECKEDIN from timereg
WHERE UNILOGIN = #unilogin
ORDER BY TIME DESC";
string connectionString = ".....";
using(SqlConnection cnn = new SqlConnection(connectionString))
using(SqlCommand checkForInOrOut = new SqlCommand(cmdText, cnn))
{
cnn.Open();
checkForInOrOut.Parameters.Add("#unilogin", SqlDbType.NVarChar).Value = publiclasses.unilogin;
// You return just one row and one column,
// so the best method to use is ExecuteScalar
object result = checkForInOrOut.ExecuteScalar();
// ExecuteScalar returns null if there is no match for your where condition
if(result != null)
{
MessageBox.Show("Login OK");
// Now convert the result variable to the exact datatype
// expected for checkedin, here I suppose you want an integer
checkedIN = Convert.ToInt32(result);
.....
}
else
MessageBox.Show("Login Failed");
}
Note how I have replaced your string concatenation with a proper use of parameters to avoid parsing problems and sql injection hacks. Finally every disposable object (connection in particular) should go inside a using block

Multiple DB Updates:

Replaces Question: Update multiple rows into SQL table
Here's a Code Snippet to update an exam results set.
DB structure is as given, but I can submit Stored Procedures for inclusion (Which are a pain to modify, so I save that until the end.)
The question: Is there a better way using SQL server v 2005.,net 2.0 ?
string update = #"UPDATE dbo.STUDENTAnswers
SET ANSWER=#answer
WHERE StudentID =#ID and QuestionNum =#qnum";
SqlCommand updateCommand = new SqlCommand( update, conn );
conn.Open();
string uid = Session["uid"].ToString();
for (int i= tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters.Clear();
updateCommand.Parameters.AddWithValue("#ID",uid);
updateCommand.Parameters.AddWithValue("#qnum",i);
updateCommand.Parameters.AddWithValue("#answer", Request.Form[i.ToString()]);
try
{
updateCommand.ExecuteNonQuery();
}
catch { }
}
A few things stand out:
You don't show where the SqlConnection is instantiated, so it's not clear that you're disposing it properly.
You shouldn't be swallowing exceptions in the loop - better to handle them in a top level exception handler.
You're instantiating new parameters on each iteration through the loop - you could just reuse the parameters.
Putting this together it could look something like the following (if you don't want to use a transaction, i.e. don't care if some but not all updates succeed):
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand updateCommand = new SqlCommand(update, conn))
{
string uid = Session["uid"].ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.Parameters.AddWithValue("#qnum", i);
updateCommand.Parameters.Add("#answer", System.Data.SqlDbType.VarChar);
for (int i = tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters["#answer"] = Request.Form[i.ToString()];
updateCommand.ExecuteNonQuery();
}
}
}
Or to use a transaction to ensure all or nothing:
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlTransaction transaction = conn.BeginTransaction())
{
using (SqlCommand updateCommand = new SqlCommand(update, conn, transaction))
{
string uid = Session["uid"].ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.Parameters.AddWithValue("#qnum", i);
updateCommand.Parameters.Add("#answer", System.Data.SqlDbType.VarChar);
for (int i = tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters["#answer"] = Request.Form[i.ToString()];
updateCommand.ExecuteNonQuery();
}
transaction.Commit();
}
} // Transaction will be disposed and rolled back here if an exception is thrown
}
Finally, another problem is that you are mixing UI code (e.g. Request.Form) with data access code. It would be more modular and testable to separate these - e.g. by splitting your application into UI, Business Logic and Data Access layers.
For 30 updates I think you're on the right track, although the comment about the need for a using around updateCommand is correct.
We've found the best performing way to do bulk updates (>100 rows) is via the SqlBulkCopy class to a temporary table followed by a stored procedure call to populate the live table.
An issue I see is when you are opening your connection.
I would at least before every update call the open and then close the connection after the update.
If your loop takes time to execute you will have your connection open for a long time.
It is a good rule to never open your command until you need it.
You can bulk insert using OpenXML. Create an xml document containing all your questions and answers and use that to insert the values.
Edit: If you stick with your current solution, I would at least wrap your SqlConnection and SqlCommand in a using block to make sure they get disposed.
emit a single update that goes against a values table:
UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (
SELECT 1 as q, 'answer1' as a
UNION ALL SELECT 2, 'answer2' -- etc...
) x ON s.QuestionNum=x.q AND StudentID=#ID
so you just put this together like this:
using(SqlCommand updateCommand = new SqlCommand()) {
updateCommand.CommandType = CommandType.Text;
updateCommand.Connection = conn;
if (cn.State != ConnectionState.Open) conn.Open();
StringBuilder sb = new StringBuilder("UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (");
string fmt = "SELECT {0} as q, #A{0} as a";
for(int i=tempStart; i<tempEnd; i++) {
sb.AppendFormat(fmt, i);
fmt=" UNION ALL SELECT {0},#A{0}";
updateCommand.Parameters.AddWithValue("#A"+i.ToString(), Request.Form[i.ToString()]);
}
sb.Append(") x ON s.QuestionNum=x.q AND StudentID=#ID");
updateCommand.CommandText = sb.ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.ExecuteNonQuery();
}
This has the advantages of being an all other nothing operation (like if you'd wrapped several updates in a transaction) and will run faster since:
The table and associated indexes are looked at/updated once
You only pay for the latency between your application and the database server once, rather than on each update

Categories