【问题标题】:How to call stored procedure in for loop using c#如何使用c#在for循环中调用存储过程
【发布时间】:2019-10-13 12:57:56
【问题描述】:

我想在循环中调用存储过程,但是使用命令查询时命令超时,但是如果使用linq然后调用存储过程会导致运行时错误:

System.Data.Entity.Core.EntityException
HResult=0x80131501
Message=在提供程序连接上启动事务时发生错误。有关详细信息,请参阅内部异常。
来源=实体框架

堆栈跟踪:
在 System.Data.Entity.Core.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel 隔离级别) 在 System.Data.Entity.Core.EntityClient.EntityConnection.BeginTransaction() 在 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](Func1 操作) 在 System.Data.Entity.Core.Objects.ObjectContext.ExecuteFunction(字符串函数名,ObjectParameter[] 参数) 在 iTax.Models.DB_iTAXEntities1.sp_Visit_Plan_Not_Found(Nullable1 operator, Nullable1 发票,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, IDictionary2 参数) 在 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext 控制器上下文,ActionDescriptor actionDescriptor,IDictionary2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d() 在 System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.c__DisplayClass46.b__3f()

内部异常 1:
SqlException: 不允许新事务,因为会话中还有其他线程在运行。

C#代码:

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

存储过程代码:

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

使用此代码但命令超时

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

【问题讨论】:

  • 一些建议。而不是 SELECT @Visit = MAX(id) FROM T-Visit ,使用 SET @Visit = SCOPE_IDENTITY()。上传实际执行计划here 并将链接添加到您的问题。这可能是T_Visit_Plan.Client 上的索引未被使用(假设存在)。
  • 不工作也不改变任何东西
  • 你在哪里发布了执行计划链接?
  • 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!

标签: sql-server asp.net-mvc entity-framework linq stored-procedures


【解决方案1】:

这一行:

var plan = M.T_Visit_Plan.Where(V => keys.Any(A => A == V.Client));

创建一个查询,但不运行它。然后这一行:

foreach (var item in plan)

运行查询并开始检索结果,但不会将它们全部加载到内存中。然后这一行:

M.sp_Visit_Plan_Not_Found . . .

尝试在用于检索结果的同一连接上运行存储过程。

解决方法很简单:在迭代之前将第一个查询的结果加载到列表中:

var planQuery = M.T_Visit_Plan.Where(V => keys.Any(A => A == V.Client));
var plan = planQuery.ToList();

【讨论】:

  • 完成,感谢您的帮助,但我有一个关于 Linq ToList() 的问题,如果返回数据而不是将此查询加载到内存?但有些时候不列出和返回数据
猜你喜欢
  • 2011-06-23
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 2020-10-11
  • 2021-02-14
相关资源
最近更新 更多