3

私は EF5 Code-first を使用しているため、System.Data.Entity.Database 型の Database プロパティを持つ DbContext があります。

私が見つけた問題は、同じパラメーターで同じ SP を複数回呼び出すと、「SqlParameter は別の SqlParameterCollection に既に含まれています」というメッセージで例外がスローされることです。

これは、以下のコードで実証できます。最初に DbContext 派生物を作成し、それをデータベースに接続します。コード内のストアド プロシージャは存在する必要はありません。SP への最初の呼び出しは、SP が存在しないというエラーになりますが、2 番目の例外は、関心のあるものです。

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 を 2 回以上呼び出す必要があります。これは有効な要件です。私の仮定では、ExecuteSqlCommand の呼び出しは非常に一時的であり、同じコンテキストで複数回実行できるはずです。

コンテキストが最初の呼び出しからのパラメーター情報にぶら下がっているようで、2 番目の呼び出しで問題が発生します。

スタック トレースは次のとおりです。

System.Data.SqlClient.SqlParameterCollection.Validate (Int32 インデックス、オブジェクト値) で System.Data.SqlClient.SqlParameterCollection.AddRange (配列値) で System.Data.Objects.ObjectContext.CreateStoreCommand (文字列 commandText、オブジェクト [] パラメーター) System.Data.Objects.ObjectContext.ExecuteStoreCommand (文字列 commandText、Object[] パラメーター) で System.Data.Entity.Internal.InternalContext.ExecuteSqlCommand (文字列 sql、Object[] パラメーター) で System.Data.Entity.Database.ExecuteSqlCommand (String sql, Object[] parameters) at EF5ExecuteSqlCommandBugReproduction.Program.Main(String[] args) in c:\EF5ExecuteSqlCommandBugReproduction\EF5ExecuteSqlCommandBugReproduction\Program.cs:line 26 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) System.AppDomain で。Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() で ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String[] args) System.Threading.ThreadHelper.ThreadStart_Context(オブジェクト状態) で System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallbackコールバック、オブジェクト状態、ブール値 preserveSyncCtx) で System.Threading.ExecutionContext.Run(ExecutionContext 実行コンテキスト、ContextCallback コールバック、オブジェクト状態、ブール値 preserveSyncCtx) で System.Threading.ExecutionContext.Run(ExecutionContext 実行コンテキスト、ContextCallback コールバック、オブジェクト状態) で System. Threading.ThreadHelper.ThreadStart()System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態、ブール値 preserveSyncCtx) での ThreadHelper.ThreadStart_Context(オブジェクト状態) System.Threading.ExecutionContext.Run(ExecutionContext 実行コンテキスト、ContextCallback コールバック、オブジェクト状態、ブール値 preserveSyncCtx) System.Threading.ThreadHelper.ThreadStart() での System.Threading.ExecutionContext.Run (ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態)System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態、ブール値 preserveSyncCtx) での ThreadHelper.ThreadStart_Context(オブジェクト状態) System.Threading.ExecutionContext.Run(ExecutionContext 実行コンテキスト、ContextCallback コールバック、オブジェクト状態、ブール値 preserveSyncCtx) System.Threading.ThreadHelper.ThreadStart() での System.Threading.ExecutionContext.Run (ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態)System.Threading.ThreadHelper.ThreadStart() で System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態) で Boolean preserveSyncCtx)System.Threading.ThreadHelper.ThreadStart() で System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態) で Boolean preserveSyncCtx)

ガイダンスをいただければ幸いです。これが EF のバグだと思われる場合は、報告します。どうもありがとう


解決策: パラメーター リストの作成と ExecuteSqlCommand をインライン関数にラップし、ExecuteSqlCommand を再呼び出しする代わりにそれを再呼び出しします。これにより、新しい SqlParameter 配列が確実に作成されます。var dc = 新しい 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();
4

2 に答える 2

3

ここに EntityFramework をインストールしていませんが、ExecuteStoreCommand メソッドが毎回新しい DbCommand オブジェクトを作成することは確かです。渡すパラメーター コレクションはフレームワーク内で作成されず、複数のコマンドで再利用されます。したがって、エラーが発生しています。

2 回目の呼び出しの前にパラメーターを複製する必要があります。

于 2012-09-04T06:41:43.937 に答える
0

パラメータを再利用しないでください。何らかの方法でコマンドに接続し、呼び出しごとに再作成しますExecuteSqlCommand

于 2012-09-04T06:25:11.993 に答える