gpt4 book ai didi

c# - 在 Where Contains 中绕过 LINQ to SQL 2100 最大参数约束

转载 作者:行者123 更新时间:2023-11-30 15:18:23 25 4
gpt4 key购买 nike

问题:我在 SQL Server 数据库上使用 SQLMetal 生成了一个 DataContext。数据库有 TableA,其中包含具有 Int64 标识符的实体。我的查询需要处理我在某些集合中查询所有具有 ID 的元素的情况。随着数据集的增长,这个集合偶尔会包含超过 2100 个 ID。

我意识到这个问题与关于该主题的其他问题类似,但我正在寻求构建扩展方法来解决该问题的帮助。

相关问题:
Avoiding the 2100 parameter limit in LINQ to SQL
Hitting the 2100 parameter limit (SQL Server) when using Contains()

我的代码看起来像这样:

var ids = new List<long>{ 1, 2, 3, /*...,*/ 2101};
var database = new MyDatabaseClass(connection)
var items = database
.TableA
.Where(x=>ids.Contains(x.RecordID))
.ToList();

并产生这个错误:

The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Too many parameters were provided in this RPC request. The maximum is 2100.

随着各种数据集的增长,我预计会经常遇到这个问题,我想创建一个可用于任何表的通用扩展。这个想法是将查询分解为更小的 Where Contains 查询,然后聚合结果。这是我展示我的想法的尝试之一:

public static List<TSource> WhereMemberInUniverse<TSource, TUniverse>(this IQueryable<TSource> source, Func<TSource, TUniverse> memberSelector, IEnumerable<TUniverse> universe)
{
var distinctUniverse = universe.Distinct().ToList();
int batchSize = 2000;

var result = new List<TSource>();

for (int i = 0; i < distinctUniverse.Count; i += batchSize)
{
var universeSlice = distinctUniverse.Skip(i).Take(batchSize);
var partialRes = source
.Where(x => universeSlice.Contains(memberSelector(x)));
result.AddRange(partialRes);
}

return result;
}

调用代码将修改为:

var ids = new List<long>{ 1, 2, 3, /*...,*/ 2101};
var database = new MyDatabaseClass(connection)
var items = database
.TableA
.WhereMemberInUniverse(x=>x.RecordID, ids);

现在这在“universeSlice.Contains”行上失败了:

Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.

似乎我所做的每一次尝试都以类似的 SQL 转换错误告终。

最佳答案

不支持的构造是 LINQ 查询表达式树中的 memberSelector(x) 调用。

要使 LINQ 查询可翻译(这基本上适用于任何 IQueryable 提供程序),您需要更改参数类型

Func<TSource, TUniverse> memberSelector

Expression<Func<TSource, TUniverse>> memberSelector

然后构建

x => universeSlice.Contains(memberSelector(x))

动态使用 System.Linq.Expressions.Expression类方法:

public static List<TSource> WhereMemberInUniverse<TSource, TUniverse>(this IQueryable<TSource> source, Expression<Func<TSource, TUniverse>> memberSelector, IEnumerable<TUniverse> universe)
{
var distinctUniverse = universe.Distinct().ToList();
int batchSize = 2000;

var result = new List<TSource>();

for (int i = 0; i < distinctUniverse.Count; i += batchSize)
{
var universeSlice = distinctUniverse.Skip(i).Take(batchSize);
//x => universeSlice.Contains(memberSelector(x))
var predicate = Expression.Lambda<Func<TSource, bool>>(
Expression.Call(
typeof(Enumerable), "Contains", new Type[] { typeof(TUniverse) },
Expression.Constant(universeSlice), memberSelector.Body
),
memberSelector.Parameters
);
var partialRes = source.Where(predicate);
result.AddRange(partialRes);
}

return result;
}

关于c# - 在 Where Contains 中绕过 LINQ to SQL 2100 最大参数约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44007662/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com