在System.Data.Entity.Database上第二次调用ExecuteSqlCommand时出错

时间:2012-09-04 06:19:44

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

我正在使用EF5 Code-first,因此我有一个带有Database属性的DbContext,类型为System.Data.Entity.Database。

我发现的问题是,当您使用相同的参数多次调用同一个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是非常短暂的,应该可以在同一个上下文中多次。

看来上下文挂在第一次调用的参数信息上,导致第二次调用的问题。

这是堆栈跟踪:

  

at System.Data.SqlClient.SqlParameterCollection.Validate(Int32 index,Object value)      在System.Data.SqlClient.SqlParameterCollection.AddRange(数组值)      at System.Data.Objects.ObjectContext.CreateStoreCommand(String commandText,Object [] parameters)      at System.Data.Objects.ObjectContext.ExecuteStoreCommand(String commandText,Object [] parameters)      在System.Data.Entity.Internal.InternalContext.ExecuteSqlCommand(String sql,Object []参数)      在System.Data.Entity.Database.ExecuteSqlCommand(String sql,Object []参数)      在EF5ExecuteSqlCommandBugReproduction.Program.Main(String [] args)中的c:\ EF5ExecuteSqlCommandBugReproduction \ EF5ExecuteSqlCommandBugReproduction \ Program.cs:第26行      在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)      在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)      在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()      在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)      at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean preserveSyncCtx)      at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean 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();

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

不要重复使用参数,它以某种方式连接到命令,为ExecuteSqlCommand

的每次调用重新创建它