如何动态构建Linq查询

时间:2013-01-16 04:44:30

标签: c# .net linq

我看到了一些旧帖子,但无法弄清楚如何实现这一点,请帮助举个例子。

我正在对DataTable运行查询以对所有列进行分组。数字列只会被称为运行时,因此我需要动态构建查询。

var newGroup = from row in dataTable.AsEnumerable() 
group row by new { ID = row.Field<string>("column1"), group1 = row.Field<string>("column2") };

我需要为n number of columns动态构建上述查询。

请解释如何通过循环列列表并构建Lambda表达式来构建ParameterExpression。

3 个答案:

答案 0 :(得分:0)

简而言之:如何实现这一点有不同的方法。困难的方法是使用表达式构建Func和Predicates的组合。更简单的方法是使用库 - LINQ Dynamic Query Library如下所述:

解决方案#1:这是一个很好的起点 - Building LINQ Queries at Runtime in C#

解决方案#2 :您应该也可以使用Linq Dynamic Query来实现此目的,因为它是为此目的而构建的 - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

答案 1 :(得分:0)

我已多次看到这个问题所以我决定创建一个博客,而不是操纵C#中的数据。我利用动态SQL从SQL数据库级别完成了大量的工作。

Here is the link。希望这会有所帮助。

答案 2 :(得分:0)

我遇到的情况是我需要为查询的左侧和右侧动态生成LINQ查询。换句话说,Where(&#34;某些属性==某些值&#34;)。我在LINQPad上玩过PredicateBuilder,并尝试了一些其他的东西,但最后LINQ动态查询库(System.Linq.Dynamic)使这个任务变得非常简单。

没有详细介绍所有细节,我所拥有的是一个方法,它接受参数,用于在MVC页面上的jqGrid上过滤和排序项目。名为QueryOptions的对象包含各种查询设置。 Data.ImportDataSearchView是绑定到后端数据库视图的实体框架实体。

通过调用:

来构建过滤器表达式
        options.FilterExpression += filterList.BuildFilterExpression<Data.ImportDataSearchView>();

BuildFilterExpression的一部分如下:

    public string BuildFilterExpression<T>()
    {
        var type = typeof(T);
        var exp = string.Empty;

        foreach (Filter filter in this)
        {
            var typeName = filter.DataType.ToLower();

            // Skip if no values
            if (!filter.Values.Any())
                continue;

            switch (typeName)
            {
                case "string":
                    // html decode string and escape single quotes
                    var stringVal = System.Web.HttpUtility.HtmlDecode(filter.Values[0]);
                    stringVal = stringVal.Replace("'", "''");

                    if (filter.Operator == Enums.FilterOperator.CONTAINS)
                        exp += string.Format("{0}.Trim().ToLower().Contains(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());

                    else if (filter.Operator == Enums.FilterOperator.DOES_NOT_EQUAL)
                        exp += string.Format("!{0}.ToLower().Equals(\"{1}\")", filter.Attribute, stringVal.ToLower());

                    else if (filter.Operator == Enums.FilterOperator.DOES_NOT_CONTAIN)
                        exp += string.Format("!{0}.Trim().ToLower().Contains(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());

                    else if (filter.Operator == Enums.FilterOperator.ENDS_WITH)
                        exp += string.Format("{0}.Trim().ToLower().EndsWith(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());

                    else if (filter.Operator == Enums.FilterOperator.EQUALS)
                        exp += string.Format("{0}.ToLower().Equals(\"{1}\")", filter.Attribute, stringVal.ToLower());

                    else if (filter.Operator == Enums.FilterOperator.STARTS_WITH)
                        exp += string.Format("{0}.Trim().ToLower().StartsWith(\"{1}\")", filter.Attribute, stringVal.Trim().ToLower());

                    break;

                //case "select": -- for dropdowns
                //case "datetime": -- for dates, etc. etc.

            // add spaces around expression
            exp = string.Format(" {0} ", exp);

            // add and/or to expression
            if (this.IndexOf(filter) != this.Count() - 1)
                exp += string.Format(" {0} ", ExpressionType.ToLower() == "and" ? "&&" : "||");
        }

        return exp;
    }

然后在构建表达式字符串后检索数据如下:

        options.OrderBy = string.IsNullOrEmpty(sortIndex) ? "TrackingId asc" : string.Format(" {0} {1} ", sortIndex, sortOrder);

        var db = new Data.BmpDB();
        var list = string.IsNullOrEmpty(options.FilterExpression)
            ? db.ImportDataSearchViews.OrderBy(options.OrderBy).ToList()
            : db.ImportDataSearchViews.Where(options.FilterExpression).OrderBy(options.OrderBy).ToList();

下面的options.FilterExpression字符串是一个三个搜索条件字段的示例,它们由方法BuildFilterExpression拼接在一起,成为LINQ where子句的一个漂亮的简单谓词字符串:

&#34; BmpName.Trim()。ToLower()。包含(\&#34; crop \&#34;)&amp;&amp; DataProviderId.ToLower()。Equals(\&#34; 123 \&#34;)&amp;&amp; StatusId == 1&#34;