I have an IDbConnection to a SQL server and two stored procedures I would like to start from a console app using the Execute method on the open connection. When I run the first one, there are no problems, but the second one takes more than 30 seconds to execute, so a Timeout is raised.
According to the Internet, waiting for a command to execute is changed with the commandTimeout parameter, but after adding the commandTimeout: 0, commandTimeout: 99999, or commandTimeout: null, both Executes raise a SQL error: String or binary data would be truncated.
These errors don't happen if I run the procedure in MS SQL Server Management Studio.
What should I do to wait for a longer time for the procedure to execute and why does adding a commandTimeout give and error about truncating?
I tried searching for a solution, but I'm not well versed in C# yet and didn't find anything useful.
Edit:
Some of you asked for tables or procedures, which I cannot give due to privacy reasons. However they are working correctly when executed in a query in the MS SQL Server Management Studio.
Here's the code in question:
public class MlCePredictedSqlSrvRepository : IMlCePredictedSqlSrvRepository
{
private IDbConnection _dbConnection;
public MlCePredictedSqlSrvRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public bool ExecuteStoredProcedure()
{
try
{
string sql = #"[dbo].[StoredProcedure]";
_dbConnection.Open();
var procedure = _dbConnection.Execute(sql, commandType: CommandType.StoredProcedure, commandTimeout: 0);
_dbConnection.Close();
Console.WriteLine("Stored Procedure successfully executed.");
return true;
}
catch (Exception ex)
{
Console.WriteLine("\tException in the Stored Procedure: " + ex.GetType().Name + "; " + ex.GetBaseException().Message);
_dbConnection.Close();
return false;
}
}
}
It's called directly in the Program. The only change from working (albeit with a Timeout) to not working is the last parameter in Execute
Related
I'm using .Net EF Core 3.1.5, I need to call an existing SQL Server stored procedure with parameters.
The procedure is executing fine and the parameter I pass in are working.
I'm having an issue whereby no warning or errors are being caught from SQL Server. My stored procedure is 'GetProcessEvents' which takes parameter #runId. If I change #runId to be #xxxxxId in my C# the stored procedure will not run but no error will be returned to my C#.
I've tried return Convert.ToInt32(cmd.ExecuteScalar()); and as in the code below 'ExecuteReader' but neither work. Even if I put a 'select 100/0' in the stored procedure no exception is returned - If I run the procedure directly in SQL Server Management Studio I get "Msg 8134, Level 16, State 1, Line 1. Divide by zero error encountered." which I would expect as an exception in C#.
try
{
if (sqlConn == null)
return 0;
DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "GetProcessEvents";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#runId", runId));
if (cmd.Connection.State != ConnectionState.Open)
cmd.Connection.Open();
var reader = cmd.ExecuteReader();
if (reader.HasRows) // I've tried with and without this if
{
while (reader.Read())
return reader.GetInt32(0);
}
return runId;
}
catch (SqlException sqle)
{
throw sqle; // No exception ever caught
}
catch (Exception e)
{
throw e;
}
Do I need to try one of the other solutions in This StackOverflow - Although I tried FromSql and Visual Studio indicates it's obsolete.
Please help. Many thanks!
Also, In case this adds anything, I'm using SignalR successfully to retrieve SQL Server warning (< less than severity 10 - so not error) events (SQL: RAISERROR ( '1' ,0, 10) WITH NOWAIT) raised from the stored procedure which fires back progress events as the possibly long running procedure is executing. This is working fine and the events are being received by C# from SQL Server.
Please Note: I have tried the above issue with and without wiring up the code below.
sqlConn.FireInfoMessageEventOnUserErrors = true;
// Number of times the stored procedure(s) will return notifications to the Client
if (percentageNotifications == null)
percentageNotifications = 10;
// Wire up delegate to SQL Server connection
sqlConn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
{
// Fire notification to SignalR Hub and anwards to client on RAISERROR (severity <10: just a message) from Sql Server
NotificationsComplete++;
_contextHub.Clients.All.SendAsync("UpdateProgressBar", taskId, ((100 / percentageNotifications) * NotificationsComplete).ToString());
};
Issue:
Basically, update statement awaits endlessly ( ExecuteNonQueryAsync() ) for some reason.
Insert works just fine, I tried to hardcode a simple update statement with hardcoded parameters(without merge), same story, even tried to remove where clause and update all rows, again, same problem.
After setting commandTimeout to 1s I managed to identiy TimeoutException, why it happens? I have no idea.
Edit: Plot twist.
Now I have randomly successful updates, which dazes me even more.
I tried basically every possible scenario I could think of to identify any patterns residing in the issue, my only conclusion is that updates success rate is totally random...
Still inserts are working just fine.
This is the simplified code portion.
public class CipCheckRepository : ICipCheckRepository
{
private string connectionString = "Data Source=****;User Id=****;PASSWORD=****;Persist Security Info=True;";
public CipCheckRepository()
{}
public async Task InsertOrUpdate(CipCheck cipCheck)
{
using (var uow = new UnitOfWork(connectionString))
{
using (var cmd = uow.CreateCommand())
{
cmd.CommandText = #"
MERGE INTO test
USING dual
ON (id = :CAD_ID)
WHEN MATCHED THEN
UPDATE SET value = :ISRA_NUMBER
WHEN NOT MATCHED THEN
INSERT
(
id,
value
)
VALUES
(
:CAD_ID,
:ISRA_NUMBER
)";
cmd.Parameters.AddWithValue("CAD_ID", 1);
cmd.Parameters.AddWithValue("ISRA_NUMBER", cipCheck.IsraNumber);
cmd.CommandTimeout = 1;
try
{
await cmd.ExecuteNonQueryAsync();
}
catch (OracleException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}
UnitOfWork class is created for abstraction matters.
How can I identify the cause of the never-ending query and what steps can be taken to prevent it?
It seems that I've been locking the table somehow, after committing all statements via Oracle Developer the quirks are gone.
I am trying to understand what's happening in the background, when a simple select query executed by client.
I am using C# Asp.Net Webforms, and i checked the processes with WireShark.
public DBC(string procedureName, params object[] procParams)
{
strError = null;
using (MySqlConnection connection = new MySqlConnection(GetConnectionString()))
{
connection.Close();
try
{
connection.Open();
MySqlCommand cmd = new MySqlCommand(procedureName, connection);
cmd.CommandType = CommandType.StoredProcedure;
//if we use params for stored procedure
if (procParams != null)
{
int i = 1;
foreach (object paramValue in procParams)
{
cmd.Parameters.Add(new MySqlParameter("#param_" + i, paramValue.ToString()));
i++;
}
}
if (procedureName.Contains("get"))
{
dtLoaded = new DataTable();
dtLoaded.Load(cmd.ExecuteReader());
}
else
{
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
strError = ErrorHandler.ErrorToMessage(ex);
}
finally
{
connection.Close();
connection.Dispose();
}
}
}
This is a simple SELECT * FROM TABLE query, in a try-catch statement. At the finally state, the connection was closed and disposed.
Why is it causes 43 process? I don't understand, why is there so much. Somebody could explain me?
Many thanks!
I assume you're using Oracle's Connector/NET. It performs a lot of not-strictly-necessary queries after opening a connection, e.g., SHOW VARIABLES to retrieve some server settings. (In 8.0.17 and later, this has been optimised slightly.)
Executing a stored procedure requires retrieving information about the stored procedure (to align parameters); it's more "expensive" than just executing a SQL statement directly. (You can disable this with CheckParameters=false, but I wouldn't recommend it.)
You can switch to MySqlConnector if you want a more efficient .NET client library. It's been tuned for performance (in both client CPU time and network I/O) and won't perform as much unnecessary work when opening a connection and executing a query. (MySqlConnector is the client library used for the .NET/MySQL benchmarks in the TechEmpower Framework Benchmarks.)
This question already has answers here:
C# & SQL Server : inserting/update only truly executes when debugging
(2 answers)
Closed 7 years ago.
I'm calling two stored procedures from a Windows service developed in C#. It should write two records in a determined table on the DB.
The stored procedures had been tested and executed from SQL Server Management Studio and they ALWAYS work well, so my problem is with the calling to them.
The weird part is that it works randomly. Some times it works just fine, but most of them time, the service doesn't execute the procedures. I had debugged it and the result of BeginExecuteNonQuery() is always "Ran To Completion", so it says that runs ok.
I'm including the code of the methods which make the calling. I don't include the stored procedures code because they are huge and as I said they always work fine when you execute it in from Management Studio with passing NULL as parameters. Of course, I don't have any connection or stored procedure naming problem.
public void Process()
{
if (!_initialized)
Initialize();
Stopped = false;
try
{
// Calling Sales sp
DoOutboundProcedure("procedure1", null, null, null);
// Calling Returns sp
DoOutboundProcedure("procedure2", null, null, null);
}
catch (Exception ex)
{
_logger.Error(ex.Message);
}
}
public void DoOutboundProcedure(string procedureName, object i_TraceOn, object i_Validate, DateTime? i_NextDateLastModified)
{
using (SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(procedureName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#i_TraceOn", SqlDbType.TinyInt).Value = i_TraceOn;
cmd.Parameters.Add("#i_Validate", SqlDbType.Bit).Value = i_Validate;
cmd.Parameters.Add("#i_NextDateLastModified", SqlDbType.DateTime).Value = i_NextDateLastModified;
con.Open();
_logger.Trace("Calling store procedure \"{0}\".", procedureName);
var result = cmd.BeginExecuteNonQuery();
_logger.Trace("Stored procedure calling finished.");
con.Close();
}
}
}
Since you're trying to do this operation asynchronously with BeginExecuteNonQuery() you have to finish the operation with EndExecuteNonQuery()
Per MSDN:
When you call BeginExecuteNonQuery to execute a Transact-SQL statement, you must call EndExecuteNonQuery in order to complete the operation. If the process of executing the command has not yet finished, this method blocks until the operation is complete. Users can verify that the command has completed its operation by using the IAsyncResult instance returned by the BeginExecuteNonQuery method. If a callback procedure was specified in the call to BeginExecuteNonQuery, this method must be called.
An example of how to use this, as taken from MSDN:
SqlCommand command = new SqlCommand(commandText, connection);
connection.Open();
IAsyncResult result = command.BeginExecuteNonQuery();
while (!result.IsCompleted)
{
Console.WriteLine("Waiting ({0})", count++);
// Wait for 1/10 second, so the counter
// does not consume all available resources
// on the main thread.
System.Threading.Thread.Sleep(100);
}
Console.WriteLine("Command complete. Affected {0} rows.",
command.EndExecuteNonQuery(result));
I have a problem at work with a simple insert method occasionally timing out due to a scheduled clean-up task on a database table. This task runs every ten minutes and during its execution my code often records an error in the event log due to 'the wait operation timed out'.
One of the solutions I'm considering is to make the code calling the stored procedure asynchronous, and in order to do this I first started looking at the BeginExecuteNonQuery method.
I've tried using the BeginExecuteNonQuery method but have found that it quite often does not insert the row at all. The code I've used is as follows:
SqlConnection conn = daService.CreateSqlConnection(dataSupport.DBConnString);
SqlCommand command = daService.CreateSqlCommand("StoredProc");
try {
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("Customer", customerId);
conn.Open();
command.BeginExecuteNonQuery(delegate(IAsyncResult ar) {
SqlCommand c = (SqlCommand)ar.AsyncState;
c.EndExecuteNonQuery(ar);
c.Connection.Close();
}, command);
} catch (Exception ex) {
LogService.WriteExceptionEntry(ex, EventLogEntryType.Error);
} finally {
command.Connection.Close();
command.Dispose();
conn.Dispose();
}
Obviously, I'm not expecting an instant insert but I am expecting it to be inserted after five minutes on a low usage development database.
I've now switched to the following code, which does do the insert:
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
using (SqlConnection conn = daService.CreateSqlConnection( dataSupport.DBConnString)) {
using (SqlCommand command = daService.CreateSqlCommand("StoredProcedure")) {
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("customer", customerId);
conn.Open();
command.ExecuteNonQuery();
}
}
});
I've got a few questions, some of them are assumptions:
As my insert method's signature is void, I'm presuming code that calls it doesn't wait for a response. Is this correct?
Is there a reason why BeginExecuteNonQuery doesn't run the stored procedure? Is my code wrong?
Most importantly, if I use the QueueUserWorkItem (or a well-behaved BeginExecuteNonQuery) am I right in thinking this will have the desired result? Which is, that an attempt to run the stored procedure whilst the scheduled task is running will see the code executing after the task completes, rather than its current timing out?
Edit
This is the version I'm using now in response to the comments and answers I've received.
SqlConnection conn = daService.CreateSqlConnection(
string.Concat("Asynchronous Processing=True;",
dataSupport.DBConnString));
SqlCommand command = daService.CreateSqlCommand("StoredProc");
command.Connection = conn;
command.Parameters.AddWithValue("page", page);
command.Parameters.AddWithValue("customer", customerId);
conn.Open();
command.BeginExecuteNonQuery(delegate(IAsyncResult ar) {
SqlCommand c = (SqlCommand)ar.AsyncState;
try {
c.EndExecuteNonQuery(ar);
} catch (Exception ex) {
LogService.WriteExceptionEntry(ex, EventLogEntryType.Error);
} finally {
c.Connection.Close();
c.Dispose();
conn.Dispose();
}
}, command);
Is there a reason why BeginExecuteNonQuery doesn't run the stored
procedure? Is my code wrong?
Probably you didn't add the Asynchronous Processing=True in the connection string.
Also - there could be a situation that when the reponse from sql is ready - the asp.net response has already sent.
that's why you need to use : Page.RegisterASyncTask (+AsyncTimeout)
(if you use webform asynchronous pages , you should add in the page directive : Async="True")
p.s. this line in :
System.Threading.ThreadPool.QueueUserWorkItem is dangerouse in asp.net apps. you should take care that the response is not already sent.