在项目中曾有这样的应用,权限筛选时先组织出员工的id,然后使用LINQ在相应的表中查询数据,条件是这些查询出来的数据的id必须在刚才权限筛选出来的id中,但是如果权限中的id太多,就会出现问题“传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。此 RPC 请求中提供了过多的参数。最多应为 2100”。我推断可能是SQLServer中使用参数不能超过2100的原因。以上描述请看下边的例子。
for (int i = 0; i < inputList.Length; i++)
{
inputList[i] = i;
}
DataClasses1DataContext dc = new DataClasses1DataContext();
var t=(from x in dc.test1
select x).Where(c=>inputList.Contains(c.testID));
dc.Log = Console.Out;
foreach (var item in t)
{
Console.WriteLine(item.testID);
}
运行以上代码会报“传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。此 RPC 请求中提供了过多的参数。最多应为 2100”异常,如果将inputList数组大小改为5,执行的sql如下:
SELECT [t0].[testID], [t0].[testContent], [t0].[p]
FROM [dbo].[test1] AS [t0]
WHERE [t0].[testID] IN (@p0, @p1, @p2, @p3, @p4)
现在问题是如果超过2100个参数怎么办,我没想出用linq实现的好办法,这里使用了一个折中的办法
{
DataClasses1DataContext dc = new DataClasses1DataContext();
dc.Log = Console.Out;
int[] inputList = new int[2100];
StringBuilder sqlstr = new StringBuilder("select * from ");
sqlstr.Append(typeof(T).Name);
sqlstr.Append(" where testid in (");
for (int i = 0; i < inputList.Length; i++)
{
sqlstr.Append(i);
if (i < inputList.Length - 1)
{
sqlstr.Append(",");
}
else
{
sqlstr.Append(")");
}
}
SqlCommand cmd = new SqlCommand(sqlstr.ToString(), (SqlConnection)dc.Connection);
dc.Connection.Open();
SqlDataReader dr = cmd.ExecuteReader();
List<T> t = dc.Translate<T>(dr).ToList();
return t;
}
static void Main(string[] args)
{
List<test1> l = MyClass.test<test1>();
foreach (var item in l)
{
Console.WriteLine(item.testID);
}
}
这里利用了反射得到表名,然后利用Linq中的Translate方法将SqlDataReader转换成相应的类。
8月11日更新:
如果inputList不是一个数组而是一个IQueryable,直接用就没什么问题
select x.testid);
var t = from x in dc.log
where tt.Contains<int?>(x.logId)
select x;
dc.Log = Console.Out;
foreach (var item in t)
{
Console.WriteLine(item.logMessage);
}
拼接出的sql语句如下:
SELECT [t0].[logId], [t0].[logMessage], [t0].[x]
FROM [dbo].[log] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[test] AS [t1]
WHERE [t1].[testid] = ([t0].[logId])
)