The Problem: I have a DataContext generated using SQLMetal on an SQL Server database. The database has TableA which contains entities with Int64 identifiers. My queries need to handle cases where I am querying for all elements with IDs in some set. As the data set has grown, this set occasional contains more than 2100 IDs.
I realize this question is similar to others that have been asked on the topic, but I am looking for help building an extension method to work around the issue.
Related questions:
Avoiding the 2100 parameter limit in LINQ to SQL
Hitting the 2100 parameter limit (SQL Server) when using Contains()
My code looks something like this:
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();
And produces this error:
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.
I anticipate running into this issue a lot as various data sets grow and I would like to create a generic extension that I can use for any table. The idea is to break up the query into smaller Where Contains queries and then aggregate the results. Here is one of my attempts to show what I am thinking:
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;
}
The calling code would be modified to:
var ids = new List<long>{ 1, 2, 3, /*...,*/ 2101};
var database = new MyDatabaseClass(connection)
var items = database
.TableA
.WhereMemberInUniverse(x=>x.RecordID, ids);
Right now this is failing on the 'universeSlice.Contains' line:
Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.
It seems that every attempt I make ends in a similar SQL translation error.