何らかの理由で、IN()句のSqlparameterが機能していません。コードは正常にコンパイルされ、パラメーターを実際の値に置き換えればクエリは機能します
StringBuilder sb = new StringBuilder();
foreach (User user in UserList)
{
sb.Append(user.UserId + ",");
}
string userIds = sb.ToString();
userIds = userIds.TrimEnd(new char[] { ',' });
SELECT userId, username
FROM Users
WHERE userId IN (@UserIds)
IN
句に必要な値ごとに1つのパラメーターを作成する必要があります。
SQLは次のようにする必要があります。
SELECT userId, username
FROM Users
WHERE userId IN (@UserId1, @UserId2, @UserId3, ...)
そのため、パラメータを作成する必要がありますandIN
ループ内のforeach
句。
次のようなもの(私の頭のうち、テストされていない):
StringBuilder sb = new StringBuilder();
int i = 1;
foreach (User user in UserList)
{
// IN clause
sb.Append("@UserId" + i.ToString() + ",");
// parameter
YourCommand.Parameters.AddWithValue("@UserId" + i.ToString(), user.UserId);
i++;
}
SQL 2008を使用している場合、テーブル値パラメーター(TVP)を受け入れるストアドプロシージャを作成し、ADO.netを使用してストアドプロシージャを実行し、それにデータテーブルを渡すことができます。
最初に、SQLサーバーでタイプを作成する必要があります。
CREATE TYPE [dbo].[udt_UserId] AS TABLE(
[UserId] [int] NULL
)
次に、この型をパラメーターとして受け入れるストアドプロシージャを作成する必要があります。
CREATE PROCEDURE [dbo].[usp_DoSomethingWithTableTypedParameter]
(
@UserIdList udt_UserId READONLY
)
AS
BEGIN
SELECT userId, username
FROM Users
WHERE userId IN (SELECT UserId FROM @UserIDList)
END
現在、.netからは、テーブル値パラメーターをまだサポートしていないため、LINQを使用できません。したがって、プレーンな古いADO.netを実行し、DataTableを取得してストアドプロシージャに渡す関数を作成する必要があります。使用する汎用関数を記述しました。何であるかに関係なく、1つのテーブル型パラメーター。
public static int ExecStoredProcWithTVP(DbConnection connection, string storedProcedureName, string tableName, string tableTypeName, DataTable dt)
{
using (SqlConnection conn = new SqlConnection(connection.ConnectionString))
{
SqlCommand cmd = new SqlCommand(storedProcedureName, conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p = cmd.Parameters.AddWithValue(tableName, dt);
p.SqlDbType = SqlDbType.Structured;
p.TypeName = tableTypeName;
conn.Open();
int rowsAffected = cmd.ExecuteNonQuery(); // or could execute reader and pass a Func<T> to perform action on the datareader;
conn.Close();
return rowsAffected;
}
}
その後、ストアドプロシージャの実際の名前を使用してこのユーティリティ関数を使用するDAL関数を記述できます。あなたの質問の例を基にして、コードは次のようになります。
public int usp_DoSomethingWithTableTypedParameter(List<UserID> userIdList)
{
DataTable dt = new DataTable();
dt.Columns.Add("UserId", typeof(int));
foreach (var userId in updateList)
{
dt.Rows.Add(new object[] { userId });
}
int rowsAffected = ExecStoredProcWithTVP(Connection, "usp_DoSomethingWithTableTypedParameter", "@UserIdList", "udt_UserId", dt);
return rowsAffected;
}
上記の「接続」パラメーターに注意してください-実際にこのタイプの関数を部分的なDataContextクラスで使用して、LINQ DataContextをTVP機能で拡張し、これらのメソッドで(var context = new MyDataContext()を使用)構文を使用します。
これは、SQL Server 2008を使用している場合にのみ機能します-うまくいけば、そうでない場合は、アップグレードする大きな理由になるかもしれません!もちろん、ほとんどの場合と大規模な本番環境では、これはそれほど簡単ではありませんが、FWIWテクノロジーを利用できる場合、これが最善の方法だと思います。
可能な「クリーナー」バージョン:
StringBuilder B = new StringBuilder();
for (int i = 0; i < UserList.Count; i++)
YourCommand.Parameters.AddWithValue("@UserId" + i.ToString(), UserList[i].UserId);
B.Append(String.Join(",", YourCommand.Parameters.Select(x => x.Name)));
SQL ServerはIN
句を次のように認識します。
_IN ('a,b,c')
_
次のように見える必要があります:
_IN ('a','b','c')
_
あなたがやろうとしていることをするより良い方法があります。
ユーザーIDがDBにある場合、IN
句は次のようにサブクエリに変更する必要があります。
IN (SELECT UserID FROM someTable WHERE someConditions)
これはハックです-インデックスではうまく機能せず、データで正しく機能するように注意する必要がありますが、過去に正常に使用しました:
_@UserIDs LIKE '%,' + UserID + ',%' -- also requires @UserID to begin and end with a comma
_