update multiple table using one query in SQL SERVER - asp.net

I am working on asp.net(c#) project with SQL SERVER 2008. I want to update three tables using one query. Please suggest me how to do that. thnaks

You can't. Update statement works for a single table. You have to write three different queries for three tables.
You can use transaction to make sure that your update statements are atomic.
BEGIN TRANSACTION
UPDATE Table1
Set Field1 = '1';
Where Field = 'value';
UPDATE Table2
Set Field1= '2'
Where Field = 'value';
UPDATE Table3
Set Field1= '3'
Where Field = 'value';
COMMIT
For C# you can use SqlTransaction. An example from the same link (bit modified)
private static void ExecuteSqlTransaction(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction("SampleTransaction");
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"UPDATE Table1 Set Field1 = '1' Where Field = 'value';";
command.ExecuteNonQuery();
command.CommandText =
"UPDATE Table2 Set Field1= '2' Where Field = 'value'";
command.ExecuteNonQuery();
command.CommandText =
"UPDATE Table3 Set Field1= '3' Where Field = 'value'";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
Console.WriteLine("Both records are written to database.");
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}

Write three queries and put them all into a single transaction, either in a stored procedure or using TransactionScope from your c# code.
using System.Transactions;
using( var ts = new TransactionScope() ){
// execute your queries
ts.Complete();
}
Full example here: http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

One of the way will be create a procedure and inside that procedure update all the table. You can also use transaction if you want to insert all the three or non of them. Here is an example
You can also maintain transaction from C#. here is an example
Transaction Stored Procedure C#
Example
using (var connection = new SqlConnection("your connectionstring"))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
try
{
using (var command1 = new SqlCommand("SP1Name", connection, transaction))
{
command1.ExecuteNonQuery();
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}

Related

How to get last incremented id in SQL with single query

My requirement I inserted successfully I want to bind last increment id to the root folder file name.id was automatic incremented in SQL. I want to bind last incremented id on that bold part place.
This is my code please help me to solve this problem:
string insert = "insert into Articles values('" + html+ "','" + text + "')";
try
{
con.Open();
SqlCommand cmd = new SqlCommand(insert, con);
int i = cmd.ExecuteNonQuery();
if (i > 0)
{
using (StreamWriter file = new StreamWriter(System.Web.Hosting.HostingEnvironment.MapPath(#"~\Articles\**ID**.html"), true))
{
file.WriteLine(value.editor); // Write the file.
}
return msg;
}
else
{
return msg1;
}
}
catch (Exception ex)
{
}
finally
{
con.Close();
}
Please note that your code is a security risk as it's vulnerable to sql injection attacks as Sean Lange rightfully wrote in the comments.
Also, the empty catch is a problem as he pointed out. Do yourself a favor and never ever use empty catch blocks.
To get the last generated identity value in the current session you should use Sql Server's SCOPE_IDENTITY() function.
Note that if you have an instead of insert trigger on the table SCOPE_IDENTITY() will not give you the correct value.
Your code should look something like this:
string insert = "insert into Articles values(#html, #text); select scope_identity()";
using (var con = new SqlConnection("<YOUR CONNECTION STRING HERE>"))
{
using (var cmd = new SqlCommand(insert, con))
{
cmd.Parameters.Add("#html", SqlDbType.NVarChar).Value = html;
cmd.Parameters.Add("#text", SqlDbType.NVarChar).Value = text;
try
{
con.Open();
var databaseId = cmd.ExecuteScalar();
if (databaseId is int)
{
using (StreamWriter file = new StreamWriter(System.Web.Hosting.HostingEnvironment.MapPath(string.Format(#"~\Articles\{0}.html", databaseId)), true))
{
file.WriteLine(value.editor); // Write the file.
}
return msg;
}
else
{
return msg1;
}
}
catch (Exception ex)
{
// Write to log, show an error message to the user
}
}
}

For Tuncating table what statement is used?

I have created one sp that tuncate table.Table name is dynamic.Here I used dynamic sql.Sp is working fine.I want to execute that sp from C#.net(from cs file).
I know executenonquery returns no of row affected.executenonquery is used for insert,update and delete command.Exectesclare is used for select which has only one cell.EceuteReader is used for selecting multiple record.What shall i use that tell my tuncate table clause executed properly or not?
You can use ExecuteNonQuery to truncate the table.
try
{
string connectionString = ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string commandText = "TRUNCATE TABLE myTable";
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.ExecuteNonQuery();
lblStatus.Text = "Table Deleted Successfully.";
}
}
}
catch(Exception ex)
{
lblStatus.Text = "Table can not be deleted, Error " + ex.Message;
}
I suppose the best way is to use ExecuteNonQuery.
1. It returs the number of rows affected by the statement.
2. And if something doesn't work properly, you will get a nice SqlException which won't go by unnoticed.
try
{
procedure.ExecuteNonQuery();
nextStep.ExecuteWhatever();
}
catch(SqlException e)
{
Console.WriteLine("Oh noes!");
}

How to SETNOCOUNTOFF from the sql query

i have a select staement which i use ExecuteNonQuery() property of SQL to return the number of affected rows. However this returns -1 all the times. I did research and realized its a result of SETNOCOUN ON property of SQL. Pls how do i off it from the query as i am not using stored procedure? Below is my code.
protected void txtName_Changed(object sender, EventArgs e)
{
string sql = "";
using (SqlCommand cmd = connection.CreateCommand())
{
sql = "SET NOCOUNT OFF;SELECT * FROM [CLIENT] WHERE cname = '" + txtName.Text + "'";
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
connection.Open();
int i = cmd.ExecuteNonQuery();
if (i > 0 )
{
txtName.BackColor = System.Drawing.ColorTranslator.FromHtml("#FD5E53");
txtName.BorderColor = System.Drawing.ColorTranslator.FromHtml("#CD4A4A");
lblError.Text = "Client Exist.";
lblError.Visible = true;
lblError.Enabled = true;
btnInsertClient.Enabled = false;
pnlAddEdit_ModalPopupExtender.Show();
// return;
}
else
{
txtName.BackColor = System.Drawing.ColorTranslator.FromHtml("#F2F0E1");
txtName.BorderColor = System.Drawing.ColorTranslator.FromHtml("#FFFFFF");
lblError.Text = "";
lblError.Visible = false;
lblError.Enabled = false;
btnInsertClient.Enabled = true;
pnlAddEdit_ModalPopupExtender.Show();
}
connection.Close();
}
}
Don't use Execute**Non**Query():
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
Try ExecuteScalar() for example:
Executes the query, and returns the first column of the first row in the result set returned by the query.
Then make your query a COUNT().
Oh, and watch out for SQL injection and repetitive code.

Data not being written to Database ASP.Net

I am building a Forum in ASP.Net but have a small problem.
I have 1 user who creates a topic and can write a post to it fine, but if another user logs in, it won't insert the post into the database. It's returning that it does but nothing inserts. The original user can login and still post but no-one else can.
this is my code in behind
protected void addPostBtn_Click(object sender, EventArgs e)
{
//Define ADO.NET objects.
string insertSQL;
string topic = Request.QueryString["topicid"].ToString();
insertSQL = "INSERT INTO Posts (TopicID, PostBody, PUserID)"
+ "VALUES (#Topic, #NewPostText, #PUserID)";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(insertSQL, con);
// Try to open the database and execute the update
int added = 0;
try
{
cmd.Parameters.AddWithValue("#Topic", topic);
cmd.Parameters.AddWithValue("#NewPostText", newPostText.InnerText);
cmd.Parameters.AddWithValue("#PUserID", Session["User_ID"]);
con.Open();
added = cmd.ExecuteNonQuery();
lblResults.Text = "Your post has been added";
}
catch (Exception err)
{
lblResults.Text = "Error inserting record. " + err.Message;
}
finally
{
con.Close();
}
if (added > 0)
{
this.BindRepeater();
}
}
I don't get any errors at all. It says it submitted fine, but it's not in the database unless the original poster does it.
EDIT:
Just realized it's to do with my view. This is my current view that it's reading from
SELECT dbo.Posts.PostBody, dbo.Posts.PostDate, dbo.Posts.PostID, dbo.[User].username, dbo.Topic.TopicID
FROM dbo.Topic RIGHT OUTER JOIN
dbo.Posts ON dbo.Topic.TopicID = dbo.Posts.TopicID LEFT OUTER JOIN
dbo.[User] ON dbo.Topic.TUserID = dbo.[User].UserID AND dbo.Posts.PUserID = dbo.[User].UserID
But it's returning NULL now for the other users names
The view needs to be as follows
SELECT dbo.Posts.PostBody, dbo.Posts.PostDate, dbo.Posts.PostID, dbo.[User].username, dbo.Topic.TopicID
FROM dbo.Topic LEFT OUTER JOIN
dbo.Posts ON dbo.Topic.TopicID = dbo.Posts.TopicID LEFT OUTER JOIN
dbo.[User] ON dbo.Posts.PUserID = dbo.[User].UserID

asp.net/sql server try catch what is going on?

I identified a bug in my code and I'm baffled as to how it could have occurred in the first place.
My question is, I found a skip in the database ID fields (it is an incremented identity field), indicating some records weren't inserted - which means my SQL sprocs (probably) threw an error. Thinking backwards from there, that means that my business object should have caught that error and thrown it, exiting immediately and returning back to the page's codebehind (instead it continued right on to the second stored procedure). I don't understand why or how this is possible. What's going on in respect to the code execution skipping my try catches?
Page code behind:
protected void submitbutton_click(object sender, EventArgs e){
try{
mybusinessobject.savetodatabase()
} catch( Exception ex) {
Response.Redirect("Error.aspx");
}
}
business object code:
public static void savetodatabase(){
int ID1=-1;
int ID2=-1;
//store the billing contact
SqlCommand cmd1 = new SqlCommand("SaveInfo1", con);
cmd1.CommandType = CommandType.StoredProcedure;
//...
cmd1.Parameters.Add("#Ret", SqlDbType.Int);
cmd1.Parameters["#Ret"].Direction = ParameterDirection.ReturnValue;
try
{
con.Open();
cmd1 .ExecuteNonQuery();
ID1 = Convert.ToInt32(cmd1.Parameters["#Ret"].Value);
}
catch (Exception ex) { throw ex; }
finally { con.Close(); }
if (ID1 > 0)
{
SqlCommand cmd = new SqlCommand("SaveInfo2", con);
cmd.CommandType = CommandType.StoredProcedure;
//...
try
{
con.Open();
cmd.ExecuteNonQuery();
ID2= Convert.ToInt32(cmd.Parameters["#Ret"].Value);
}
catch (Exception ex) { throw ex; }
finally { con.Close(); }
}
}
SQL Code:
PROCEDURE [dbo].[SaveInfo1]
(
-- ... parameters ...
)
AS
INSERT INTO Table1 ( ... ) Values ( ... )
RETURN SCOPE_IDENTITY
PROCEDURE [dbo].[SaveInfo2]
(
-- ... parameters ...
)
AS
DECLARE #SpecialID INT
INSERT INTO Table2 ( ... ) Values ( ... )
SET #SpecialID = SCOPE_IDENTITY()
INSERT INTO Table3 ( [ID], ... ) Values ( #SpecialID, ... )
RETURN SCOPE_IDENTITY()
Your exception handling is horrible. Never do this:
catch (Exception ex) { throw ex; }
All that accomplishes is to screw up the stack trace in the exception. It makes it look like the exception originated at the point of the throw.
Never do this:
try{
mybusinessobject.savetodatabase()
} catch( Exception ex) {
Response.Redirect("Error.aspx");
}
You don't know what exception happened. You have no idea whether or not it's safe to redirect, and on top of it all, you lose all information about what the exception was!
You should also get into the habit of implementing using blocks:
public static void savetodatabase()
{
using (SqlConnection con = new SqlConnection("Connectionstring"))
{
int ID1;
//store the billing contact
using (SqlCommand cmd1 = new SqlCommand("SaveInfo1", con))
{
cmd1.CommandType = CommandType.StoredProcedure;
//...
cmd1.Parameters.Add("#Ret", SqlDbType.Int);
cmd1.Parameters["#Ret"].Direction = ParameterDirection.ReturnValue;
con.Open();
cmd1.ExecuteNonQuery();
ID1 = Convert.ToInt32(cmd1.Parameters["#Ret"].Value);
}
if (ID1 <= 0)
{
return;
}
int ID2 = -1;
using (SqlCommand cmd = new SqlCommand("SaveInfo2", con))
{
cmd.CommandType = CommandType.StoredProcedure;
//...
con.Open();
cmd.ExecuteNonQuery();
ID2 = Convert.ToInt32(cmd.Parameters["#Ret"].Value);
}
}
}
A using block will ensure that the resource will have its Dispose method called, whether or not an exception is thrown.
Isn't the more likely scenario that someone just deleted some records from the table?
If records are deleted, their unique identifiers will not be recycled, even when new records are later inserted. You can use RESEED in SQL to reset the identity seed to 0 if you desire, but I suggest against that unless you wipe the table. Otherwise you could end up with primary key violations.
Also, make sure your column's identity seed is set to increment 1 at a time.
Your code doesn't matter, just go to Web.config and play with appropriate node:
<customErrors mode="On|Off" />
P.S.
Use the using clause to auto-close a connection, instead of manual in the finally clause
you can test the catch. just change the procedure:
PROCEDURE [dbo].[SaveInfo1]
(
-- ... parameters ...
)
AS
INSERT INTO Table1 ( ... ) Values ( ..., some_out_of_range_value_here, ....)
RETURN SCOPE_IDENTITY()
to have some hard coded out of range value (so the insert fails), and then run your application...

Resources