如果您使用的是 SQL 2008,您可以创建一个接受表值参数 (TVP) 的存储过程,并使用 ADO.net 执行该存储过程并将数据表传递给它:
首先,您需要在 SQL server 中创建类型:
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,并将其传递给存储过程:我编写了一个通用函数,我使用它可以对任何存储过程执行此操作,只要它只需要一个表格类型的参数,不管它是什么;
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 我认为如果你有可用的技术,这是最好的方法。