使用LINQ以动态方式过滤产品

时间:2012-08-09 19:08:22

标签: asp.net linq dictionary code-behind dynamicquery

经过几个小时的尝试和搜索,我认为是时候与你分享我的问题了。

问题定义: 我有一个 KeyValuePairs字典(名为 filterPool ),其中包含一个整数( PropertyID )和一个字符串( McValue )。我想要做的是根据KeyValuePairs过滤产品并将它们作为 DataTable / List 返回。 您可以将此视为构建动态“Where ... And ..”子句为SQL。

以下是我正在使用的代码:

            foreach (KeyValuePair<int, string> filter in filterPool)
            {
                products = products.Where(i => i.PROPERTYID == filter.Key && i.MCVALUE.Equals(filter.Value));
            }
            return products.ToDataTable();                  

问题是上面的foreach循环似乎只运行一次,对于Dictionary中可用的最新KeyValuePair。

据我所知,在Stackoverflow上,我问题的最接近的解决方案是:this one, also using a Dictionary of values for filtering

必须有办法实现使用Dictionary和LINQ过滤的目标;或者有一件很重要的事情,我不知道/忽视了什么。

希望所给出的问题足够清楚, 谢谢 ^^

3 个答案:

答案 0 :(得分:2)

这是一个关闭问题。你可以通过临时解决它:

        foreach (KeyValuePair<int, string> filterTmp in filterPool)
        {
            var filter = filterTmp; // Make a temporary
            products = products.Where(i => i.PROPERTYID == filter.Key && i.MCVALUE.Equals(filter.Value));
        }
        return products.ToDataTable();   

有关正在发生的事情的详细信息,请参阅Eric Lippert的帖子Closing over the loop variable considered harmful

另请注意,C#5的此行为已更改。在C#5 / VS2012中,此代码将按预期工作。

答案 1 :(得分:1)

您在foreach的每次迭代中都会覆盖您的产品系列。我不确定你的收藏中的数据类型是什么,但你要在foreach中做这样的事情:

products.AddRange(products.Where(i => i.PROPERTYID == filter.Key && i.MCVALUE.Equals(filter.Value)));

我不确定这是否合理,但您似乎正在尝试创建一个包含与您的filterPool相匹配的产品的集合。

答案 2 :(得分:0)

我认为使用聚合更好地解决了这个问题:

return filter
    .Aggregate(products, (acc, filter) => acc.Where(i => i.PROPERTYID == filter.Key && i.MCVALUE.Equals(filter.Value)));
    .ToDataTable();