【问题标题】:Error calling ExecuteSqlCommand the second time on System.Data.Entity.Database在 System.Data.Entity.Database 上第二次调用 ExecuteSqlCommand 时出错
【发布时间】:2012-09-04 06:19:43
【问题描述】:

我使用的是 EF5 代码优先,因此我有一个带有 System.Data.Entity.Database 类型的数据库属性的 ​​DbContext。

我发现的问题是,当你用相同的参数多次调用同一个SP时,它会抛出一个异常消息:“SqlParameter已经被另一个SqlParameterCollection包含”。

这可以用下面的代码来演示。首先创建一个 DbContext 派生并将其连接到数据库。代码中的存储过程不必存在。 第一次调用 SP 会报错说 SP 不存在,然而,第二个例外是我们感兴趣的。

var pa = new SqlParameter[] 
        { 
            new SqlParameter("@Name", SqlDbType.NVarChar) { Value = "test" }
        };
        var dc = new MyWebContext(); // derived from DbContext
        try
        {
            dc.Database.ExecuteSqlCommand("spImport @Name", pa);
        }
        catch { }
        dc.Database.ExecuteSqlCommand("spImport @Name", pa); // fails with "The SqlParameter is already contained by another SqlParameterCollection"

有时,我确实需要用相同的参数调用同一个 SP 两次或更多次。这是一个有效的要求。我的假设是调用 ExecuteSqlCommand 是非常短暂的,应该可以在同一个上下文中多次调用。

上下文似乎挂在第一次调用的参数信息上,导致第二次出现问题。

这是堆栈跟踪:

在 System.Data.SqlClient.SqlParameterCollection.Validate(Int32 索引,对象值) 在 System.Data.SqlClient.SqlParameterCollection.AddRange(数组值) 在 System.Data.Objects.ObjectContext.CreateStoreCommand(字符串命令文本,对象 [] 参数) 在 System.Data.Objects.ObjectContext.ExecuteStoreCommand(字符串命令文本,对象 [] 参数) 在 System.Data.Entity.Internal.InternalContext.ExecuteSqlCommand(字符串 sql,对象 [] 参数) 在 System.Data.Entity.Database.ExecuteSqlCommand(String sql,Object[] 参数) 在 c:\EF5ExecuteSqlCommandBugReproduction\EF5ExecuteSqlCommandBugReproduction\Program.cs:line 26 中的 EF5ExecuteSqlCommandBugReproduction.Program.Main(String[] args) 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数) 在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ThreadHelper.ThreadStart()

我将不胜感激任何指导。如果您认为这是 EF 的错误,那么我会报告它。 非常感谢


解决方案: 将参数列表创建和 ExecuteSqlCommand 封装到一个内联函数中,然后重新调用它,而不是重新调用 ExecuteSqlCommand。这将确保创建一个新的 SqlParameter 数组。 var dc = new SpondleWebContext(); // 派生自 DbContext

        Action act = () =>
        {
            var pa = new SqlParameter[]  { new SqlParameter("@Name", SqlDbType.NVarChar) { Value = "test" } };
            dc.Database.ExecuteSqlCommand("spImport @Name", pa);
        };

        try { act(); } catch { }
        act();

【问题讨论】:

标签: c# entity-framework ado.net entity-framework-5


【解决方案1】:

我没有在此处安装 EntityFramework,但我非常确定 ExecuteStoreCommand 方法每次都会创建一个新的 DbCommand 对象。您传递的参数集合不是在框架内创建的,而是由多个命令重用。因此你得到了错误。

您必须在第二次调用之前克隆参数。

【讨论】:

  • 好吧,那是一个奇怪的无证“功能”!我现在已经在一个内联函数中完成了参数列表的创建和 ExecuteSqlCommand 函数调用,并重新使用了它。我认为这是不正确的行为。 ExecuteSqlCommand 应该是暂时的。感谢您的帮助
  • 不客气。我不太喜欢这类东西的原因之一。为什么不使用您编写的新方法更新问题?它可能会帮助其他在搜索时来到此帖子的人。
【解决方案2】:

不要重用参数,它以某种方式连接到命令,为ExecuteSqlCommand的每个调用重新创建它

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 2012-06-26
    • 2018-05-04
    相关资源
    最近更新 更多