简体   繁体   中英

What is the best approach to build dynamic LINQ queries?

Thanks to those who answered my last couple questions, I got the following code to work which allows you to send a collection of Where clauses to a method which are all attached to a LINQ query. This is going to work for the case at hand that I need.

However, what is the best approach to extend this so that:

  • OrderBy clauses can be sent
  • Where clauses can be combined with "OR" logic and not only with "AND" logic
  • other options can be sent dynamically, eg what fields are included in the object sent back (eg so that it does not always have to be Customer, in the example below)

Basically, the background of this is to be able to dynamically build a LINQ query from this form a parsed configuration file or from user input.

The task reminds me of building classes which could dynamically produce SQL statements based on parameters, but that involved building a string (SQL Statement) which was more straight-forward than dynamically building a LINQ query.

There are many Stackoverflow questions and blog posts about this topic, but they each seem to be individual solutions to individual problems, but is there an API or library that is emerging as a standard for building dynamic LINQ queries, eg so I can easily take a DSL syntax and translate it into LINQ, eg "FirstName startswith 'a' and (state='co' or state='ca')"?

using System;
using System.Collections.Generic;
using System.Linq;

namespace TestDynamicLinq2343
{
    public class Program
    {
        static void Main(string[] args)
        {
            List<Customer> customers = Customer.GetCustomers();

            List<Func<Customer, bool>> whereClauses = new List<Func<Customer, bool>>();
            whereClauses.Add(c => c.LastName.ToUpper().Contains("A"));
            whereClauses.Add(c => c.FirstName.ToUpper().Contains("O"));
            whereClauses.Add(c => c.FirstName.ToUpper().Contains("E"));

            foreach (var customer in Customer.GetFilteredCustomers(customers, whereClauses))
            {
                Console.WriteLine(customer.LastName);
            }

            Console.ReadLine();
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Street { get; set; }
        public string Location { get; set; }
        public string ZipCode { get; set; }

        public static List<Customer> GetCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { FirstName = "Jim", LastName = "Jones" });
            customers.Add(new Customer { FirstName = "Joe", LastName = "Adams" });
            customers.Add(new Customer { FirstName = "Jake", LastName = "Johnson" });
            customers.Add(new Customer { FirstName = "Angie", LastName = "Reckar" });
            customers.Add(new Customer { FirstName = "Jean", LastName = "Anderson" });
            return customers;
        }

        public static List<Customer> GetFilteredCustomers(List<Customer> customers, List<Func<Customer, bool>> whereClauses)
        {
            IEnumerable<Customer> dbCustomers = customers;
            foreach (var whereClause in whereClauses)
            {
                dbCustomers = dbCustomers.Where(whereClause);
            }
            return dbCustomers.ToList();
        }
    }
}

Dynamic query building is somehow tedious task. Please visit PredicateBuilder . You can get insights on how dynamic quires are built.

I can certainly second the suggestion of PredicateBuilder as a useful tool, and is the best way around the OR problem. There is also the Microsoft Dynamic LINQ library which I have used occasionally, and might work with your suggestion of passing clauses from a config file.

In most cases when I have needed some element of dynamic querying I have usually ended up coding for particular problems directly much as you have done above. I have a couple of quite complex functions in live systems that start with a basic root query, and then add a number of extra Where and OrderBy clauses dependant on the parameters passed to the function.

Although most of the LINQ examples seem to show relatively simple queries, the LINQ libraries are pretty powerful allowing you to gradually build up your query step by step, and then only generating the actual query when it is executed, hence I tend to favour just using chained operators rather than the query comprehension syntax.

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