<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Erik Pourali</title>
    <description>The latest articles on DEV Community by Erik Pourali (@eriksoftwaredev).</description>
    <link>https://dev.to/eriksoftwaredev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1340524%2F6d4ff3e7-3033-4771-91e0-ecdf67bbd009.png</url>
      <title>DEV Community: Erik Pourali</title>
      <link>https://dev.to/eriksoftwaredev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eriksoftwaredev"/>
    <language>en</language>
    <item>
      <title>Dynamic Querying in C#: Real-World Scenarios and Techniques</title>
      <dc:creator>Erik Pourali</dc:creator>
      <pubDate>Thu, 14 Mar 2024 10:42:12 +0000</pubDate>
      <link>https://dev.to/eriksoftwaredev/dynamic-querying-in-c-real-world-scenarios-and-techniques-66i</link>
      <guid>https://dev.to/eriksoftwaredev/dynamic-querying-in-c-real-world-scenarios-and-techniques-66i</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg40ow01lxltg0f1pewcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg40ow01lxltg0f1pewcm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine crafting a library app where users effortlessly find books by title, author, or genre. Traditional search methods drown you in code. But fear not! Dynamic Querying in C# saves the day.&lt;/p&gt;

&lt;p&gt;✅In our tale, crafting separate search methods for each book attribute becomes a headache. The code becomes a labyrinth of nested if or switch case statements, a nightmare to navigate:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public IEnumerable&amp;lt;Book&amp;gt; GetBooks(string propertyToFilter, string keyword)
{
    switch (propertyToFilter)
    {
        case "Title":
            return await _books.Where(e =&amp;gt; e.Title == keyword).ToListAsync();
        case "Author":
            return await _books.Where(e =&amp;gt; e.Author == keyword).ToListAsync();
        case "Genre":
            return await _books.Where(e =&amp;gt; e.Genre == keyword).ToListAsync();
        // More cases for other properties
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As your library expands, this code morphs into a tangled mess, crumbling under the weight of evolving requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Dynamic Queries, wielding their power alongside generics:
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

IQueryable&amp;lt;T&amp;gt; TextFilter&amp;lt;T&amp;gt;(IQueryable&amp;lt;T&amp;gt; source, string keyword)
{
    // The instructions and information in the rest of this article
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can apply this method to any entity, searching for the keyword within all string properties. Additionally, you have the flexibility to extend the method to support other data types.&lt;/p&gt;

&lt;p&gt;Break free from rigid conditions. Seamlessly adapt to changing data structures. Navigate complex filters with ease.&lt;/p&gt;




&lt;p&gt;In the dynamic landscape of software development, scenarios often arise where the nature of queries needs to adapt based on runtime conditions. This article explores various techniques in C# for executing different queries depending on runtime states using &lt;em&gt;IQueryable&lt;/em&gt; and expression trees. We’ll dive into a real-world scenario and demonstrate how to implement dynamic querying with practical examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Download the source code on my GitHub:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/eriksoftwaredev/LinkedInPostsCodeDemos/blob/master/DynamicQuerying/Program.cs" rel="noopener noreferrer"&gt;&lt;em&gt;Source Code&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding IQueryable and Expression Trees
&lt;/h2&gt;

&lt;p&gt;Before delving into real-world examples, let’s briefly understand the fundamentals. An &lt;em&gt;IQueryable&lt;/em&gt; in C# consists of two main components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expression:&lt;/strong&gt; A language- and datasource-agnostic representation of the current query’s components, depicted as an expression tree.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Provider:&lt;/strong&gt; An instance of a LINQ provider, responsible for materializing the query into a value or set of values.&lt;br&gt;
In dynamic querying, the provider remains constant while the expression tree evolves with each query.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are various techniques for executing different queries depending on runtime states:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1. Using Runtime State within the Expression Tree&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;2. Calling Additional LINQ Methods&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;3. Varying the Expression Tree Passed into LINQ Methods&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;4. Constructing Expression Trees Using Factory Methods&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;5. Adding Method Call Nodes to IQueryable’s Expression Tree&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;6. Leveraging the &lt;a href="https://dynamic-linq.net/" rel="noopener noreferrer"&gt;Dynamic LINQ Library&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Scenario: Managing Employee Data
&lt;/h2&gt;

&lt;p&gt;Consider a scenario where you have an HR application with employee data, each having different attributes such as salary, department, and performance rating. HR administrators want the ability to dynamically filter and analyze employee data based on various criteria. The challenge is to build a flexible querying system that can handle diverse employee attributes and dynamic user inputs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

var employees = new List&amp;lt;Employee&amp;gt;
{
    new(Firstname: "Alice", Lastname: "Williams", Salary: 60000, Department: "IT", PerformanceRating: 4),
    new(Firstname: "Bob", Lastname: "Brown", Salary: 75000, Department: "HR", PerformanceRating: 3),
    new(Firstname: "Charlie", Lastname: "Taylor", Salary: 50000, Department: "Finance", PerformanceRating: 5),
};
var employeeSource = employees.AsQueryable();

record Employee(string Firstname, string Lastname, decimal Salary, string Department, int? PerformanceRating);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Techniques for Dynamic Querying
&lt;/h2&gt;

&lt;p&gt;Now, let’s explore various techniques to handle dynamic querying based on user input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Using Runtime State within the Expression Tree&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a scenario where administrators want to filter employees based on dynamic salary ranges:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

decimal minSalary = 55000;
decimal maxSalary = 75000;

var employeeQuery = employeeSource
    .Where(x =&amp;gt; x.Salary &amp;gt;= minSalary &amp;amp;&amp;amp; x.Salary &amp;lt;= maxSalary);

Console.WriteLine(string.Join(",", employeeQuery.Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Alice Williams,Bob Brown


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This method provides a direct way to adapt queries based on simple runtime conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Calling Additional LINQ Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Administrators might also want to sort employees dynamically based on performance ratings:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

bool sortByRating = true;
employeeQuery = employeeSource;

if (sortByRating)
    employeeQuery = employeeQuery.OrderBy(x =&amp;gt; x.PerformanceRating);

Console.WriteLine(string.Join(",", employeeQuery.Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Bob Brown,Alice Williams,Charlie Taylor


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This approach allows for the conditional application of various LINQ methods, tailoring queries to specific runtime scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Varying the Expression Tree Passed into LINQ Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With LINQ methods in .NET, you can use different expressions based on runtime state.&lt;/p&gt;

&lt;p&gt;In this scenario, administrators want to filter employees based on both department and performance ratings dynamically:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

using System.Linq.Expressions;

string targetDepartment = "IT";
int? targetRating = 4;

Expression&amp;lt;Func&amp;lt;Employee, bool&amp;gt;&amp;gt; expr = (targetDepartment, targetRating) switch
{
    ("" or null, null) =&amp;gt; x =&amp;gt; true,
    (_, null) =&amp;gt; x =&amp;gt; x.Department.Equals(targetDepartment),
    ("" or null, _) =&amp;gt; x =&amp;gt; x.PerformanceRating &amp;gt;= targetRating,
    (_, _) =&amp;gt; x =&amp;gt; x.Department.Equals(targetDepartment) &amp;amp;&amp;amp; x.PerformanceRating &amp;gt;= targetRating
};

employeeQuery = employeeSource.Where(expr);

Console.WriteLine(string.Join(",", employeeQuery.Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Alice Williams


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This technique provides a flexible way to construct expressions dynamically based on multiple runtime conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Constructing Expression Trees Using Factory Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until now, we’ve been dealing with examples where we knew the type of element and query at compile time — specifically, using strings and &lt;em&gt;IQueryable&lt;/em&gt;. However, you might need to modify a query for different element types or add components based on the element type. You can build expression trees from scratch using methods in &lt;em&gt;System.Linq.Expressions.Expression&lt;/em&gt; to customize the expression at runtime for a specific element type.&lt;/p&gt;

&lt;p&gt;Before exploring our scenario, let’s introduce the process of constructing an &lt;em&gt;Expression&lt;/em&gt;. Follow these steps:&lt;/p&gt;

&lt;p&gt;1) Import the necessary namespace:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

using System.Linq.Expressions;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;2) Create ParameterExpression objects for each parameter in your lambda expression using the Parameter factory method:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ParameterExpression parameter = Expression.Parameter(typeof(string), "x");


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;3) Build the body of your &lt;em&gt;LambdaExpression&lt;/em&gt; using the &lt;em&gt;ParameterExpression(s)&lt;/em&gt; you’ve defined and the factory methods provided by Expression. For example, you can construct an expression like &lt;em&gt;x.StartsWith(“a”)&lt;/em&gt; as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Expression body = Expression.Call(
    parameter,
    typeof(string).GetMethod("StartsWith", new[] { typeof(string) }),
    Expression.Constant("a")
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;4) Enclose the parameters and body within an &lt;em&gt;Expression&lt;/em&gt; with compile-time type, using the suitable Lambda factory method overload:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Expression&amp;lt;Func&amp;lt;string, bool&amp;gt;&amp;gt; lambda = Expression.Lambda&amp;lt;Func&amp;lt;string, bool&amp;gt;&amp;gt;(body, parameter);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;5) Compile the lambda expression to get the delegate:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Func&amp;lt;string, bool&amp;gt; function = lambda.Compile();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;6) Here’s the complete example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

using System;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        // Step 2: Define ParameterExpression objects for each parameter
        ParameterExpression parameter = Expression.Parameter(typeof(string), "x");

        // Step 3: Construct the body of your LambdaExpression
        Expression body = Expression.Call(
            parameter,
            typeof(string).GetMethod("StartsWith", new[] { typeof(string) }),
            Expression.Constant("a")
        );

        // Step 4: Wrap parameters and body in an Expression&amp;lt;TDelegate&amp;gt;
        Expression&amp;lt;Func&amp;lt;string, bool&amp;gt;&amp;gt; lambda = Expression.Lambda&amp;lt;Func&amp;lt;string, bool&amp;gt;&amp;gt;(body, parameter);

        // Step 5: Compile the lambda expression to get the delegate
        Func&amp;lt;string, bool&amp;gt; function = lambda.Compile();

        // Test the compiled function
        bool result = function("apple");
        Console.WriteLine(result); // Output: True
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Our scenario:&lt;/p&gt;

&lt;p&gt;Consider having two entity types:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

record Employee(string Firstname, string Lastname, decimal Salary, string Department, int? PerformanceRating);

record Task(string Title, string Description);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You want to filter and retrieve entities with a specific text in one of their string fields.&lt;/p&gt;

&lt;p&gt;For Task, you’d search in Title and Description properties:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

string term1 = "Project abc";
var tasksQry = new List&amp;lt;Task&amp;gt;()
    .AsQueryable()
    .Where(x =&amp;gt; x.Description.Contains(term1) || x.Title.Contains(term1));


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For Employee, in Name and Department properties:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

string term2 = "Alice";
var employeesQry = new List&amp;lt;Employee&amp;gt;()
    .AsQueryable()
    .Where(x =&amp;gt; x.Firstname.Contains(term2) || x.Lastname.Contains(term2));


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instead of creating separate functions for &lt;em&gt;IQueryable&lt;/em&gt; and &lt;em&gt;IQueryable&lt;/em&gt;, the following function lets you add this filtering to any existing query, regardless of the specific element type:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

using System.Reflection;

string employeeSearchKeyword = "Alice";
string taskSearchKeyword = "Project abc";

IQueryable&amp;lt;T&amp;gt; TextFilter&amp;lt;T&amp;gt;(IQueryable&amp;lt;T&amp;gt; source, string term)
{
    if (string.IsNullOrEmpty(term))
        return source;

    // T stands for the type of element in the query, decided at compile time
    Type elementType = typeof(T);

    // Retrieve all string properties from this specific type
    PropertyInfo[] stringProperties =
        elementType.GetProperties()
            .Where(x =&amp;gt; x.PropertyType == typeof(string))
            .ToArray();
    if (!stringProperties.Any())
        return source;

    // Identify the correct String.Contains overload
    MethodInfo containsMethod =
        typeof(string).GetMethod("Contains", new[] { typeof(string) })!;

    // Create a parameter for the expression tree, represented as 'x' in 'x =&amp;gt; x.PropertyName.Contains("term")'
    // Define a ParameterExpression object
    ParameterExpression prm = Expression.Parameter(elementType);

    // Map each property to an expression tree node
    IEnumerable&amp;lt;Expression&amp;gt; expressions = stringProperties
        .Select&amp;lt;PropertyInfo, Expression&amp;gt;(prp =&amp;gt;
            // Construct an expression tree node for each property, like x.PropertyName.Contains("term")
            Expression.Call( // .Contains(...) 
                Expression.Property( // .PropertyName
                    prm, // x 
                    prp
                ),
                containsMethod,
                Expression.Constant(term) // "term" 
            )
        );

    // Combine all the resulting expression nodes using || (OR operator).
    Expression body = expressions
        .Aggregate(
            (prev, current) =&amp;gt; Expression.Or(prev, current)
        );

    // Encapsulate the expression body in a compile-time-typed lambda expression
    Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; lambda =
        Expression.Lambda&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt;(body, prm);

    // Because the lambda is compile-time-typed (albeit with a generic parameter), we can use it with the Where method
    return source.Where(lambda);
}

employeeQuery = TextFilter(employeeSource, employeeSearchKeyword);
Console.WriteLine(string.Join(",", employeeQuery.Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Alice Williams

var taskQuery = TextFilter(taskSource, taskSearchKeyword);
Console.WriteLine(string.Join(",",
    taskQuery.Select(x =&amp;gt; $"Task Detail:\n\tTitle: {x.Title}\n\tDescription: {x.Description}\n")));
// Output: Task Detail:
//              Title: Project abc Status Report
//              Description: give a quick summary of how the project has gone before the time period


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This method enables the creation of complex queries dynamically, accommodating various search criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Adding Method Call Nodes to IQueryable’s Expression Tree&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re working with &lt;em&gt;IQueryable&lt;/em&gt; instead of &lt;em&gt;IQueryable&lt;/em&gt;, you can’t easily use the generic LINQ methods. One way around this is to construct the inner expression tree as mentioned earlier and then use reflection to call the right LINQ method while giving it the expression tree.&lt;/p&gt;

&lt;p&gt;Another option is to copy what the LINQ method does by putting the whole tree in a &lt;em&gt;MethodCallExpression&lt;/em&gt; that acts like a call to the LINQ method.&lt;/p&gt;

&lt;p&gt;In a scenario where administrators want to filter employees based on dynamic conditions and handle untyped queries:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

IQueryable TextFilter_Untyped(IQueryable source, string term)
{
    if (string.IsNullOrEmpty(term))
        return source;

    Type elementType = source.ElementType;

    // Retrieve all string properties from this specific type
    PropertyInfo[] stringProperties =
        elementType.GetProperties()
            .Where(x =&amp;gt; x.PropertyType == typeof(string))
            .ToArray();
    if (!stringProperties.Any())
        return source;

    // Identify the correct String.Contains overload
    MethodInfo containsMethod =
        typeof(string).GetMethod("Contains", new[] { typeof(string) })!;

    // Create a parameter for the expression tree, represented as 'x' in 'x =&amp;gt; x.PropertyName.Contains("term")'
    // Define a ParameterExpression object
    ParameterExpression prm = Expression.Parameter(elementType);

    // Map each property to an expression tree node
    IEnumerable&amp;lt;Expression&amp;gt; expressions = stringProperties
        .Select&amp;lt;PropertyInfo, Expression&amp;gt;(prp =&amp;gt;
            // Construct an expression tree node for each property, like x.PropertyName.Contains("term")
            Expression.Call( // .Contains(...) 
                Expression.Property( // .PropertyName
                    prm, // x 
                    prp
                ),
                containsMethod,
                Expression.Constant(term) // "term" 
            )
        );

    // Combine all the resulting expression nodes using || (OR operator).
    Expression body = expressions
        .Aggregate(
            (prev, current) =&amp;gt; Expression.Or(prev, current)
        );
    if (body is null)
        return source;

    Expression filteredTree = Expression.Call(
        typeof(Queryable),
        "Where",
        new[] { elementType },
        source.Expression,
        Expression.Lambda(body, prm!)
    );

    return source.Provider.CreateQuery(filteredTree);
}

var eQuery = TextFilter_Untyped(employeeSource, "Charlie");

Console.WriteLine("5. Adding Method Call Nodes to IQueryable's Expression Tree:");
Console.WriteLine(string.Join(",", eQuery.Cast&amp;lt;Employee&amp;gt;().Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Charlie Taylor


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this scenario, when you don’t have a compile-time &lt;em&gt;T&lt;/em&gt; generic placeholder, utilize the Lambda overload that doesn’t necessitate compile-time type information. This results in the creation of a LambdaExpression instead of an &lt;em&gt;Expression&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; This approach facilitates the dynamic application of filtering logic to &lt;em&gt;IQueryable&lt;/em&gt; without compile-time type information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Leveraging the Dynamic LINQ Library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Making expression trees using factory methods is hard. It’s simpler to put together strings. The &lt;a href="https://dynamic-linq.net/" rel="noopener noreferrer"&gt;Dynamic LINQ library&lt;/a&gt; has extra methods for &lt;em&gt;IQueryable&lt;/em&gt; that match regular LINQ ones, but they use strings with a special format instead of expression trees. The library turns the string into the right expression tree and gives back the translated &lt;em&gt;IQueryable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Get the &lt;a href="https://dynamic-linq.net/" rel="noopener noreferrer"&gt;Dynamic LINQ library&lt;/a&gt; from NuGet:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

dotnet add package System.Linq.Dynamic.Core --version 1.3.10


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Import the necessary namespace:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

using System.Linq.Dynamic.Core;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In a scenario where administrators want a simpler way to compose queries using string syntax:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

IQueryable TextFilter_Strings(IQueryable source, string term) {
    if (string.IsNullOrEmpty(term)) 
     return source; 

    var elementType = source.ElementType;

    // Retrieve all string properties from this specific type
    var stringProperties = 
        elementType.GetProperties()
            .Where(x =&amp;gt; x.PropertyType == typeof(string))
            .ToArray();
    if (!stringProperties.Any()) { return source; }

    // Build the string expression
    string filterExpr = string.Join(" || ",
        stringProperties.Select(prp =&amp;gt; $"{prp.Name}.Contains(@0)"));

    return source.Where(filterExpr, term);
}

var qry = TextFilter_Untyped(employeeSource, "HR");

Console.WriteLine("6. Leveraging the Dynamic LINQ Library:");
Console.WriteLine(string.Join(",", qry.Cast&amp;lt;Employee&amp;gt;().Select(x =&amp;gt; $"{x.Firstname} {x.Lastname}")));
// Output: Bob Brown


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; The Dynamic LINQ library simplifies the construction of dynamic queries by accepting string expressions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dynamic querying in C# offers powerful tools for adapting queries to varying runtime conditions. By understanding &lt;em&gt;IQueryable&lt;/em&gt; and expression trees, developers can create flexible and efficient systems that respond dynamically to user input. The real-world scenario of an employee management system demonstrates the practical application of these techniques in building robust and adaptable software solutions. Choose the appropriate method based on the complexity of your scenario, and empower your applications with dynamic querying capabilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  The whole source on my GitHub:
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/eriksoftwaredev/LinkedInPostsCodeDemos/blob/master/DynamicQuerying/Program.cs" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/how-to-use-expression-trees-to-build-dynamic-queries" rel="noopener noreferrer"&gt;Querying based on runtime state (C#)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>aspnet</category>
    </item>
  </channel>
</rss>
