私は 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();