简体   繁体   中英

How to build a Linq Query Dynamically

I have see a few old post but cannot figure out how to achieve this, Please help with an example.

I am running a query on a DataTable to group all the columns. The number columns will only be known as runtime hence I need to build the query dynamically.

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

I need to build the above query dynamically for n number of columns .

Please explain how can I build the ParameterExpression by looping over the columns list and build a Lambda expression.

In short: There are different ways on how to achieve this. The hard way is to build the combination of Func and Predicates by using the expressions. The more easier way is the utilization of library - LINQ Dynamic Query Library mentioned below:

Solution # 1: Here is a good start point to look - Building LINQ Queries at Runtime in C#

Solution # 2: you should be also able to do this by using Linq Dynamic Query , as it build for this purposes - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library) .

I've saw this question many times so I decided to create a blog but instead of manipulating the data from C#. I've done the heavy lefting from the SQL database level by utilizing dynamic SQL.

Here is the link . Hope this helps.

I had a situation where I needed to produce a LINQ query dynamically for both the left side and right side of the query. So in other words, Where("some property == some value"). I played around with PredicateBuilder from the guys at LINQPad, and tried a few other things, but in the end the LINQ Dynamic Query Library (System.Linq.Dynamic) made this task very simple.

Without going through all the details, what I have is a method that takes parameters for filtering and sorting items on a jqGrid on an MVC page. An object called QueryOptions holds various query settings. Data.ImportDataSearchView is the Entity Framework entity that is tied to a database view on the backend.

The filter expression is build up by calling:

        options.FilterExpression += filterList.BuildFilterExpression<Data.ImportDataSearchView>();

Part of BuildFilterExpression is as follows:

    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;
    }

And then data was retrieved as follows, after building up the expression string:

        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();

The options.FilterExpression string below is an example of three search criteria fields pieced together by the method BuildFilterExpression into a nice, simple predicate string for the LINQ where clause:

"BmpName.Trim().ToLower().Contains(\\"crops\\") && DataProviderId.ToLower().Equals(\\"123\\") && StatusId == 1"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM