ASP.NET Execute SQL Server stored procedure multiple times async - c#

I am calling a stored procedure via ASP.NET now I am trying to call it 200 times async, I am trying to do this by adding a transaction, however its not working out, here is my code:
try
{
using (connection = new SqlConnection(connectionString))
{
connection.Open();
transaction = connection.BeginTransaction();
for (int i = 0; i < 200; i++)
{
using (SqlCommand command = new SqlCommand("TimeSlotAppointments", connection))
{
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
SqlParameter parameter1 = command.Parameters.Add("#StartTime", SqlDbType.DateTime);
parameter1.Direction = ParameterDirection.Input;
parameter1.Value = DateTime.Now;
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
}
catch (SqlException e)
{
Console.Write(e);
transaction.Rollback();
}
finally
{
connection.Close();
connection.Dispose();
}
I am passing the current date and time as a parameter and when I check out the results in SQL Server I am expecting the #StartTime to be the same, but they are not, close, but the milliseconds increase for each record, am I going about this the wrong way? What I am trying to accomplish is executing the store procedure 200 times simultaneously.

The start time value is different because you are assigning the value inside the loop and in every iteration, the time has changed (a few milliseconds as you mentioned). If you want to use the same value for all calls, then you need to store the time stamp outside the loop in a variable and use that value in your loop.
This is how your code should look like:
try
{
using (connection = new SqlConnection(connectionString))
{
connection.Open();
transaction = connection.BeginTransaction();
var startTime = DateTime.Now; // I added this line
for (int i = 0; i < 200; i++)
{
using (SqlCommand command = new SqlCommand("TimeSlotAppointments", connection))
{
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
SqlParameter parameter1 = command.Parameters.Add("#StartTime", SqlDbType.DateTime);
parameter1.Direction = ParameterDirection.Input;
parameter1.Value = startTime; // I changed this line
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
}
catch (SqlException e)
{
Console.Write(e);
transaction.Rollback();
}
finally
{
connection.Close();
connection.Dispose();
}

Related

.NET SQL client stored procedure call empty statement

I have a .NET 6 C# app that calls three stored procedures on a SQL Server. Two of these calls work ok, but the third gives a null ref exception at the line:
result = (bool)cmd.ExecuteScalar();
using (var con1 = this.GetSqlConnection())
{
bool result = false;
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = OnlinePaymentCheckNurseryChildSProc;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con1;
cmd.Parameters.AddRange(param);
LogSqlParams(cmd.Parameters);
con1.Open();
result = (bool)cmd.ExecuteScalar();
LogInfo(methodName, $"result=:{result}");
LogInfo(methodName, $"Leaving:{methodName}");
return result;
}
catch (Exception ex)
{
LogError(ex, methodName, "Trouble checking nursery child");
return false;
}
}
The stored proc ends with:
IF (#d = #DOB)
BEGIN
SET #Return = 1
END
ELSE
BEGIN
SET #Return = 0
END
RETURN #Return
END
I've called the same stored procedure with the same parameters from SQL Server Management Studio and it works ok.
The key to solving this problem was to use the ExecuteNonQuery method and pass a special param with a "Direction" property of ParameterDirection.ReturnValue.
The working code block can be see below:
using (var con1 = this.GetSqlConnection())
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = OnlinePaymentCheckNurseryChildSProc;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con1;
cmd.Parameters.AddRange(param);
LogSqlParams(cmd.Parameters);
SqlParameter returnValue = new SqlParameter();
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
con1.Open();
await cmd.ExecuteNonQueryAsync();
int result = (int)returnValue.Value;
LogInfo(methodName, $"result=:{result}");
LogInfo(methodName, $"Leaving:{methodName}");
return result == 1 ? true : false;
}
catch (Exception ex)
{
LogError(ex, methodName, "Trouble checking nursery child");
return false;
}
}

Unable to update database table using Asp.net MVC

I'm trying to update a column in a database table based on count however it keeps returning a value of 0 and not increment. When the user clicks the approve button then the line number should be updated using this method This is what I have so far.
public void SetRequisitionStatus0(List <string> reqNumbers, List <string> item_no)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
command.CommandText = "requisition_sp_setstatus0";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#reqNumber", SqlDbType.VarChar);
command.Parameters.Add("#item_no", SqlDbType.VarChar);
//command.Parameters.Add("#ApprovedBy", SqlDbType.VarChar);
command.Parameters.Add("#approve_date", SqlDbType.DateTime).Value = DateTime.Now;
command.Parameters.Add("#line_num", SqlDbType.Int);
using (command.Connection = connection)
{
try
{
connection.Open();
for (int i = 0; i < reqNumbers.Count; i++)
{
command.Parameters["#reqNumber"].Value = reqNumbers[i];
command.Parameters["#item_no"].Value = item_no[i];
command.Parameters["#line_num"].Value = i;
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
connection.Close();
}
}
return;
}

Should I call Parameters.Clear when reusing a SqlCommand with a transation?

I'm coding a transaction manually in ADO.NET. The example I'm working from reuses the SqlCommand which seem like a fine idea.
However, I have added parameters to my command.
My question is: in the following code, is command.Parameters.Clear() correct? Or am I doing it wrong?
using (var connection = new SqlConnection(EomAppCommon.EomAppSettings.ConnStr))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
SqlCommand command = connection.CreateCommand();
command.Transaction = transaction;
try
{
foreach (var itemIDs in this.SelectedItemIds)
{
command.CommandText = "UPDATE Item SET payment_method_id = #batchID WHERE id in (#itemIDs)";
// IS THE FOLLOWING CORRECT?
command.Parameters.Clear();
command.Parameters.Add(new SqlParameter("#batchID", batchID));
command.Parameters.Add(new SqlParameter("#itemIDs", itemIDs));
command.ExecuteNonQuery();
}
transaction.Commit();
}
catch (Exception ex)
{
MessageBox.Show("Failed to update payment batches, rolling back." + ex.Message);
try
{
transaction.Rollback();
}
catch (Exception exRollback)
{
if (!(exRollback is InvalidOperationException)) // connection closed or transaction already rolled back on the server.
{
MessageBox.Show("Failed to roll back. " + exRollback.Message);
}
}
}
}
Since you're repeatedly executing the same query, it's unnecessary to clear them - you can add the parameters outside the loop and just fill them inside.
try
{
command.CommandText = "UPDATE Item SET payment_method_id = #batchID WHERE id in (#itemIDs)";
command.Parameters.Add(new SqlParameter("#batchID", 0));
command.Parameters.Add(new SqlParameter("#itemIDs", ""));
foreach (var itemIDs in this.SelectedItemIds)
{
command.Parameters["#batchID"].Value = batchID;
command.Parameters["#itemIDs"].Value = itemIDs;
command.ExecuteNonQuery();
}
transaction.Commit();
}
Note - you can't use parameters with IN as you've got here - it won't work.
In this condition you need it as you need set new parameters values, so its correct.
By the way, move
command.CommandText = ".."
outside of the loop too, as it's never changed.

Delete in oracle 10g from asp.net web site - wait on commint?

I need delete data in oracle 10g database from ASP.NET 2.0 web site.
Method DeleteMonthPlan I use on execute delete command. Problem is that this command is executing long time "in browser" and finally delete command is not executed. Maybe it waits on commit? What is root of problem?
This SQL command DELETE C_PPC_PLAN WHERE MFG_MONTH='VALUE' is OK.
MFG_MONTH column type is VARCHAR2(16)
First I need call method DeleteMonthPlan and than I need call InsertDatePlan.
private static void DeleteMonthPlan(string monthIndex)
{
try
{
using (var conn = new OracleConnection(GenerateConnectionString()))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = string.Format("DELETE C_PPC_PLAN WHERE MFG_MONTH='{0}'", monthIndex);
cmd.ExecuteNonQuery();
}
}
catch (Exception exception)
{
throw exception;
}
}
For example this method I use on insert and it is OK.
public void InsertDatePlan(DatePlan dp,
string monthIndex)
{
DeleteMonthPlan(monthIndex);
try
{
using (var conn = new OracleConnection(GenerateConnectionString()))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.Parameters.Add(":Site", OracleType.VarChar).Value = dp.Site;
cmd.Parameters.Add(":Week", OracleType.VarChar).Value = dp.MfgWeek;
cmd.Parameters.Add(":Month", OracleType.VarChar).Value = dp.MfgMonth;
cmd.Parameters.Add(":Year", OracleType.VarChar).Value = dp.MfgYear;
cmd.Parameters.Add(":Input", OracleType.Number).Value = dp.Input;
cmd.Parameters.Add(":Output", OracleType.Number).Value = dp.Output;
cmd.Parameters.Add(":LMUser", OracleType.VarChar).Value = dp.LmUser;
cmd.Parameters.Add(":PartNo", OracleType.VarChar).Value = dp.PartNo;
cmd.Parameters.Add(":PartNoDesc", OracleType.VarChar).Value = dp.PartNoDesc;
cmd.CommandText = string.Format("INSERT INTO C_PPC_PLAN (CREATE_TIME, SITE, MFG_DAY,MFG_WEEK,MFG_MONTH,MFG_YEAR,INPUT,OUTPUT,LM_TIME,LM_USER,PART_NO,PART_NO_DESC)"
+ " VALUES (to_date('{0}', 'dd-mm-yyyy hh24:mi:ss'), :Site ,to_date('{1}', 'dd-mm-yyyy hh24:mi:ss'),:Week,"
+ ":Month,:Year,:Input,:Output,to_date('{2}', 'dd-mm-yyyy hh24:mi:ss'),:LMUser,:PartNo,:PartNoDesc)"
, dp.CreateTime, dp.MfgDate, dp.LmTime);
cmd.ExecuteNonQuery();
}
}
catch (Exception exception)
{
throw exception;
}
}
I tried use transaction. I call this method on the bottom but is never finish it means that part
trans.Rollback(); or conn.Close(); is never executed.
private static void DeleteMonthPlan(string monthIndex)
{
var conn = new OracleConnection(GenerateConnectionString());
conn.Open();
OracleCommand cmd= conn.CreateCommand();
OracleTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = trans;
try
{
cmd.CommandText = "DELETE C_PPC_PLAN WHERE MFG_MONTH='6'";
cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception e)
{
trans.Rollback();
}
finally
{
conn.Close();
}
}
try
DELETE FROM C_PPC_PLAN WHERE MFG_MONTH='6'
BTW your code uses "literals" in some places instead of bind variables (params) which makes it vulnerable to SQL injection which is a really serious security problem!

Transactions in C#

In addition to this question: Preorder tree traversal copy folder
I was wondering if it is possible to create a transaction that contains different calls to the database.
ex:
public bool CopyNode(int nodeId, int parentNode)
{
// Begin transaction.
try
{
Method1(nodeId);
Method2(nodeId, parentNode);
Method3(nodeId);
}
catch (System.Exception ex)
{
//rollback all the methods
}
}
I don't know if this is possible. We are using subsonic to do the database calls.
This is really important, not only for the tree traversal problem but also for some other stuff we do.
The main idea is that we can't let our dabase get corrupted with uncomplete data.
That is possible, you can find a example here
Or perhaps a transaction scope...
http://msdn.microsoft.com/en-us/library/ms172152.aspx
BeginTransaction is called off a ADO.NET collection object.
The Command object needs this transaction (SqlTransaction object) assigned to it.
Commit and Rollback are only called in the outer method.
Check out this code. It works by re-using the SqlConnection and SqlTransaction objects. This is a classic Master>Details type of set up. The master type is ColumnHeaderSet which contains a property of
List<ColumnHeader>
, which is the details (collection).
Hope this helps.
-JM
public static int SaveColumnHeaderSet(ColumnHeaderSet set)
//save a ColumnHeaderSet
{
string sp = ColumnSP.usp_ColumnSet_C.ToString(); //name of sp we're using
SqlCommand cmd = null;
SqlTransaction trans = null;
SqlConnection conn = null;
try
{
conn = SavedRptDAL.GetSavedRptConn(); //get conn for the app's connString
cmd = new SqlCommand(sp, conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
trans = conn.BeginTransaction();
cmd.Transaction = trans; // Includes this cmd as part of the trans
//parameters
cmd.Parameters.AddWithValue("#ColSetName", set.ColSetName);
cmd.Parameters.AddWithValue("#DefaultSet", 0);
cmd.Parameters.AddWithValue("#ID_Author", set.Author.UserID);
cmd.Parameters.AddWithValue("#IsAnonymous", set.IsAnonymous);
cmd.Parameters.AddWithValue("#ClientNum", set.Author.ClientNum);
cmd.Parameters.AddWithValue("#ShareLevel", set.ShareLevel);
cmd.Parameters.AddWithValue("#ID_Type", set.Type);
//add output parameter - to return new record identity
SqlParameter prm = new SqlParameter();
prm.ParameterName = "#ID_ColSet";
prm.SqlDbType = SqlDbType.Int;
prm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
int i = Int32.Parse(cmd.Parameters["#ID_ColSet"].Value.ToString());
if (i == 0) throw new Exception("Failed to save ColumnHeaderSet");
set.ColSetID = i; //update the object
//save the ColumnHeaderList (SetDetail)
if (ColumnHeader_Data.SaveColumnHeaderList(set, conn, trans)==false) throw new Exception("Failed to save ColumnHeaderList");
trans.Commit();
// return ID for new ColHdrSet
return i;
}
catch (Exception e){
trans.Rollback();
throw e;
}
finally{
conn.Close();
}
}
public static bool SaveColumnHeaderList(ColumnHeaderSet set, SqlConnection conn, SqlTransaction trans)
//save a (custom)ColHeaderList for a Named ColumnHeaderSet
{
// we're going to accept a SqlTransaction to maintain transactional integrity
string sp = ColumnSP.usp_ColumnList_C.ToString(); //name of sp we're using
SqlCommand cmd = null;
try
{
cmd = new SqlCommand(sp, conn); // re-using the same conection object
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = trans; // includes the cmd in the transaction
//build params collection (input)
cmd.Parameters.Add("#ID_ColSet", SqlDbType.Int);
cmd.Parameters.Add("#ID_ColHeader", SqlDbType.Int);
cmd.Parameters.Add("#Selected", SqlDbType.Bit);
cmd.Parameters.Add("#Position", SqlDbType.Int);
//add output parameter - to return new record identity
//FYI - #return_value = #ID_SavedRpt
SqlParameter prm = new SqlParameter();
prm.ParameterName = "#ID";
prm.SqlDbType = SqlDbType.Int;
prm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prm);
//Loop
foreach (ColumnHeader item in set.ColHeaderList)
{
//set param values
cmd.Parameters["#ID_ColSet"].Value = set.ColSetID;
cmd.Parameters["#ID_ColHeader"].Value = item.ColHeaderID;
cmd.Parameters["#Selected"].Value = item.Selected;
cmd.Parameters["#Position"].Value = item.Position;
cmd.ExecuteNonQuery();
int i = Int32.Parse(cmd.Parameters["#ID"].Value.ToString());
if (i == 0) throw new Exception("Failed to save ColumnHeaderSet");
}
return true;
}
catch (Exception e)
{
throw e;
}
}

Categories

Resources