I want call a stored procedure in a loop, but command time out when use command query, but if use linq then call stored procedure causes a runtime error:
System.Data.Entity.Core.EntityException
HResult=0x80131501
Message=An error occurred while starting a transaction on the provider connection. See the inner exception for details.
Source=EntityFrameworkStackTrace:
at System.Data.Entity.Core.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel) at System.Data.Entity.Core.EntityClient.EntityConnection.BeginTransaction() at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass4b.<ExecuteFunction>b__49() at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func
1 operation) at System.Data.Entity.Core.Objects.ObjectContext.ExecuteFunction(String functionName, ObjectParameter[] parameters) at iTax.Models.DB_iTAXEntities1.sp_Visit_Plan_Not_Found(Nullable1 operator, Nullable
1 invoice, Nullable1 client) in D:\Projects\iTAX\source code\iTax\Models\Model1.Context.cs:line 564 at iTax.Controllers.Follow_UpController.Visit() in D:\Projects\iTAX\source code\iTax\Controllers\Follow_UpController.cs:line 290 at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary
2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult
2.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.b__3f()Inner Exception 1:
SqlException: New transaction is not allowed because there are other threads running in the session.
C# code:
var form = Request.Form;
var ops = long.Parse(form["Operator"]);
var keys = form.AllKeys.Where(A=> !A.Contains("Operator")).Select(A => long.Parse(A));
var plan = M.T_Visit_Plan.Where(V => keys.Any(A => A == V.Client));
int i = 0;
foreach (var item in plan)
M.sp_Visit_Plan_Not_Found(ops, M.T_Invoice.Where(A => A.Client == item.Client).Max(A => A.id), item.Client);
return RedirectToAction("Visit", new { Operator = ops });
Stored procedure code:
ALTER PROCEDURE [dbo].[sp_Visit_Plan_Not_Found]
@Operator BIGINT = 0,
@Invoice BIGINT = 0,
@Client BIGINT = 0
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO T_Visit (Operator, Invoice, Date, Mode, Client)
VALUES (@Operator,@Invoice, GETDATE(), 5, @Client)
DECLARE @Visit BIGINT
SELECT @Visit = MAX(id)
FROM T_Visit
UPDATE T_Visit_Plan
SET Visit = @Visit
WHERE (Client = @Client)
END
Use this code but time out command
public static void Visit_Plan_Not_Found(long ops, long invoice, long client)
{
SqlConnection con = new SqlConnection(new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings["DB_iTAXEntities1"].ConnectionString).ProviderConnectionString);
using (con)
{
string query = @"INSERT INTO T_Visit
(Operator, Invoice, Date, Mode, Client)
VALUES (@Operator, @Invoice, GETDATE(), 5, @Client)
DECLARE @Visit BIGINT
SELECT @Visit = MAX(id)
FROM T_Visit
UPDATE T_Visit_Plan
SET Visit = scope_identity()
WHERE (Client = @Client)";
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.Add("@Operator", SqlDbType.BigInt).Value = ops;
cmd.Parameters.Add("@Invoice", SqlDbType.BigInt).Value = invoice;
cmd.Parameters.Add("@Client", SqlDbType.BigInt).Value = client;
if (cmd.Connection.State == ConnectionState.Closed) con.Open();
cmd.ExecuteNonQuery();
if (cmd.Connection.State == ConnectionState.Open) con.Close();
}
}
}
This line:
var plan = M.T_Visit_Plan.Where(V => keys.Any(A => A == V.Client));
creates a query, but does not run it. Then this line:
foreach (var item in plan)
Runs the query and begins retrieving the results, but does not load them all into memory. Then this line:
M.sp_Visit_Plan_Not_Found . . .
Tries to run a stored procedure on the same connection that's being used to retrieve the results.
The fix is simple: Load the results of the first query into a list before you iterate them:
var planQuery = M.T_Visit_Plan.Where(V => keys.Any(A => A == V.Client));
var plan = planQuery.ToList();
User contributions licensed under CC BY-SA 3.0