我正在尝试创建一个通用函数来帮助我使用LINQ to SQL从本地列表中选择数千条记录。SQL Server(至少2005)将查询限制为2100个参数,我想选择的记录更多。
这将是一个很好的示例用法:
var some_product_numbers = new int[] { 1,2,3 ... 9999 }; Products.SelectByParameterList(some_product_numbers, p => p.ProductNumber);
这是我的(无效)实现:
public static IEnumerable<T> SelectByParameterList<T, PropertyType>(Table<T> items, IEnumerable<PropertyType> parameterList, Expression<Func<T, PropertyType>> property) where T : class { var groups = parameterList .Select((Parameter, index) => new { GroupID = index / 2000, //2000 parameters per request Parameter } ) .GroupBy(x => x.GroupID) .AsEnumerable(); var results = groups .Select(g => new { Group = g, Parameters = g.Select(x => x.Parameter) } ) .SelectMany(g => /* THIS PART FAILS MISERABLY */ items.Where(item => g.Parameters.Contains(property.Compile()(item))) ); return results; }
我已经看到了很多使用表达式构建谓词的示例。在这种情况下,我只想执行委托以返回当前ProductNumber的值。或者更确切地说,我想将此转换为SQL查询(以非泛型形式正常工作)。
我知道编译表达式只会使我回到平方(将委托作为Func传递),但是我不确定如何将参数传递给“未编译”表达式。
谢谢你的帮助!
**编辑:让我进一步说明:
这是我要概括的工作示例:
var local_refill_ids = Refills.Select(r => r.Id).Take(20).ToArray(); var groups = local_refill_ids .Select((Parameter, index) => new { GroupID = index / 5, //5 parameters per request Parameter } ) .GroupBy(x => x.GroupID) .AsEnumerable(); var results = groups .Select(g => new { Group = g, Parameters = g.Select(x => x.Parameter) } ) .SelectMany(g => Refills.Where(r => g.Parameters.Contains(r.Id)) ) .ToArray() ;
此SQL代码中的结果:
SELECT [t0].[Id], ... [t0].[Version] FROM [Refill] AS [t0] WHERE [t0].[Id] IN (@p0, @p1, @p2, @p3, @p4) ... That query 4 more times (20 / 5 = 4)
最简单的方法:使用LINQKit(免费的非限制性许可证)
工作版本的代码:
public static IEnumerable<T> SelectByParameterList<T, PropertyType>(this Table<T> items, IEnumerable<PropertyType> parameterList, Expression<Func<T, PropertyType>> propertySelector, int blockSize) where T : class { var groups = parameterList .Select((Parameter, index) => new { GroupID = index / blockSize, //# of parameters per request Parameter } ) .GroupBy(x => x.GroupID) .AsEnumerable(); var selector = LinqKit.Linq.Expr(propertySelector); var results = groups .Select(g => new { Group = g, Parameters = g.Select(x => x.Parameter) } ) .SelectMany(g => /* AsExpandable() extension method requires LinqKit DLL */ items.AsExpandable().Where(item => g.Parameters.Contains(selector.Invoke(item))) ); return results; }
用法示例:
Guid[] local_refill_ids = Refills.Select(r => r.Id).Take(20).ToArray(); IEnumerable<Refill> results = Refills.SelectByParameterList(local_refill_ids, r => r.Id, 10); //runs 2 SQL queries with 10 parameters each
再次感谢你的帮助!