1

I have a list of categories, and i am creating a dynamic query.

var Categories = GetCategories(); //list of string
query = query.Where(x => x.CategoryID == ?????);

Now how can i make the categories list have an OR operator on each category inside the where clause?

Like for example, lets assume Categories list has two categories. So it will be like:

query = query.Where(x => x.CategoryID == Categories[0] | x.CategoryID == Categories[1]);

but this has to be dynamic.

zvikow
  • 21
  • 2

4 Answers4

1

you could do it like this

query.Where(x => Categories.Contains(x.CategoryID))
pbachman
  • 934
  • 2
  • 11
  • 18
0

It looks like you need to use Expression Trees (C#)

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y.

You can compile and run code represented by expression trees. This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries. For more information about expression trees in LINQ, see How to use expression trees to build dynamic queries (C#).

Here is a very simple example to start from:

The following code example demonstrates how to compile an expression tree and run the resulting code.

    // Creating an expression tree.  
    Expression<Func<int, bool>> expr = num => num < 5;  

    // Compiling the expression tree into a delegate.  
    Func<int, bool> result = expr.Compile();  

    // Invoking the delegate and writing the result to the console.  
    Console.WriteLine(result(4));  

    // Prints True.  

    // You can also use simplified syntax  
    // to compile and run an expression tree.  
    // The following line can replace two previous statements.  
    Console.WriteLine(expr.Compile()(4));  

    // Also prints True.

Here is an example of how to use expression trees to build dynamic queries How to use expression trees to build dynamic queries (C#):

The following example shows you how to use expression trees to construct a query against an IQueryable data source and then execute it. The code builds an expression tree to represent the following query:

   companies.Where(company => (company.ToLower() == "coho winery" ||
       company.Length > 16))
          .OrderBy(company => company)

The factory methods in the System.Linq.Expressions namespace are used to create expression trees that represent the expressions that make up the overall query. The expressions that represent calls to the standard query operator methods refer to the Queryable implementations of these methods. The final expression tree is passed to the CreateQuery(Expression) implementation of the provider of the IQueryable data source to create an executable query of type IQueryable. The results are obtained by enumerating that query variable.

// Add a using directive for System.Linq.Expressions.  

string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",  
                   "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",  
                   "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",  
                   "Blue Yonder Airlines", "Trey Research", "The Phone Company",  
                   "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };  

// The IQueryable data to query.  
IQueryable<String> queryableData = companies.AsQueryable<string>();  

// Compose the expression tree that represents the parameter to the predicate.  
ParameterExpression pe = Expression.Parameter(typeof(string), "company");  

// ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****  
// Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.  
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));  
Expression right = Expression.Constant("coho winery");  
Expression e1 = Expression.Equal(left, right);  

// Create an expression tree that represents the expression 'company.Length > 16'.  
left = Expression.Property(pe, typeof(string).GetProperty("Length"));  
right = Expression.Constant(16, typeof(int));  
Expression e2 = Expression.GreaterThan(left, right);  

// Combine the expression trees to create an expression tree that represents the  
// expression '(company.ToLower() == "coho winery" || company.Length > 16)'.  
Expression predicateBody = Expression.OrElse(e1, e2);  

// Create an expression tree that represents the expression  
// 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'  
MethodCallExpression whereCallExpression = Expression.Call(  
    typeof(Queryable),  
    "Where",  
    new Type[] { queryableData.ElementType },  
    queryableData.Expression,  
    Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));  
// ***** End Where *****  

// ***** OrderBy(company => company) *****  
// Create an expression tree that represents the expression  
// 'whereCallExpression.OrderBy(company => company)'  
MethodCallExpression orderByCallExpression = Expression.Call(  
    typeof(Queryable),  
    "OrderBy",  
    new Type[] { queryableData.ElementType, queryableData.ElementType },  
    whereCallExpression,  
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));  
// ***** End OrderBy *****  

// Create an executable query from the expression tree.  
IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);  

// Enumerate the results.  
foreach (string company in results)  
    Console.WriteLine(company);  

/*  This code produces the following output:  

    Blue Yonder Airlines  
    City Power & Light  
    Coho Winery  
    Consolidated Messenger  
    Graphic Design Institute  
    Humongous Insurance  
    Lucerne Publishing  
    Northwind Traders  
    The Phone Company  
    Wide World Importers  
*/
V. S.
  • 1,086
  • 14
  • 14
0

I hope this solution helps in case my original answer suggesting using Expression Trees is not useful:

The code

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

namespace ConsoleApp39
{
    class Program
    {
        public struct CategoryEntry {
            public int Id { get; set; }
            public string Description { get; set; }
        }

        static void Main(string[] args)
        {
            var categories = new List<CategoryEntry>();
            categories.Add(new CategoryEntry() { Id = 1, Description = "1-First"});
            categories.Add(new CategoryEntry() { Id = 1, Description = "1-Second" });
            categories.Add(new CategoryEntry() { Id = 2, Description = "2-First" });
            categories.Add(new CategoryEntry() { Id = 3, Description = "3-First" });

            var categoryIDs = new HashSet<int>();
            categoryIDs.Add(1);
            categoryIDs.Add(2);

            Console.WriteLine("The sought Ids \n");
            foreach (var categoryId in categoryIDs) {
                Console.WriteLine(categoryId);
            }
            Console.WriteLine("\n");

            // returns a collection of collections, one collection per queried category id
            var result = categoryIDs.Select(id => categories.FindAll(c => c.Id == id));
            Console.WriteLine("The result from the variable result \n");
            foreach (var collection in result)
            {
                collection.ForEach(entry => Console.WriteLine(entry.Description));
            }

            Console.WriteLine("\n");
            // returns a single collection with all found categories for all queried categories ids 
            var flatResult = categoryIDs.SelectMany(id => categories.FindAll(c => c.Id == id));
            Console.WriteLine("The result from the variable flatResult \n");
            foreach (var entry in flatResult)
            {
                Console.WriteLine(entry.Description);
            }

            Console.ReadLine();
        }
    }
}

The output

The sought Ids

1 2

The result from the variable result

1-First 1-Second 2-First

The result from the variable flatResult

1-First 1-Second 2-First

V. S.
  • 1,086
  • 14
  • 14
0

I ended up doing this and it worked.

var subChildCategories = GetChildCategories(Convert.ToInt32(getProductsDomainModel.CategoryID));
var parameter = Expression.Parameter(typeof(FullProductDomainModel));
BinaryExpression binaryExpression = null;

foreach (var category in subChildCategories)
{
    var prop = Expression.Property(parameter, "CategoryID");
    var value = Expression.Constant(category.ToString());
    var newBinary = Expression.MakeBinary(ExpressionType.Equal, prop, value);

    binaryExpression =
        binaryExpression == null
        ? newBinary
        : Expression.MakeBinary(ExpressionType.Or, binaryExpression, newBinary);
}

var cookedExpression = Expression.Lambda<Func<FullProductDomainModel, bool>>(binaryExpression, parameter).Compile();

query = query.Where(cookedExpression).AsQueryable();
zvikow
  • 21
  • 2