DynamicWhere.ex 1.4.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package DynamicWhere.ex --version 1.4.3                
NuGet\Install-Package DynamicWhere.ex -Version 1.4.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DynamicWhere.ex" Version="1.4.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DynamicWhere.ex --version 1.4.3                
#r "nuget: DynamicWhere.ex, 1.4.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DynamicWhere.ex as a Cake Addin
#addin nuget:?package=DynamicWhere.ex&version=1.4.3

// Install DynamicWhere.ex as a Cake Tool
#tool nuget:?package=DynamicWhere.ex&version=1.4.3                

DynamicWhere.ex

Description

DynamicWhere.ex is a powerful and versatile library for dynamically creating complex filter expressions in Entity Framework Core applications. This library enhances your EF Core queries by providing support for creating dynamic filters using objects, making it easier to generate complex queries for your data.

With DynamicWhere.ex, you can easily define and apply conditions, logical connectors, and intersections to filter data from your database. It offers a flexible way to construct dynamic filter expressions for various data types, including text, numbers, booleans, and date-time values, using a wide range of logical operators.

Installation

You can install the library via NuGet. Run the following command in your project's NuGet Package Manager console:

Install-Package DynamicWhere.ex

Getting Started

Getting started with the library is straightforward. Simply install it via NuGet, and you're ready to create dynamic filter expressions for your Entity Framework Core queries.

Usage

DynamicWhere.ex provides enums, classes, and extension methods to simplify the construction of dynamic filter expressions. You can define conditions, condition groups, and sets using objects, allowing you to specify complex filtering logic in a structured way.

Enums

The DynamicWhere.ex library includes the following enums to support dynamic querying capabilities:

DataType

The DataType enum provides support for various data types when defining conditions in dynamic queries. It includes the following values:

  • Text: Represents textual data.
  • Number: Represents numeric data.
  • Boolean: Represents boolean data.
  • DateTime: Represents date and time data.
  • Guid: Represents globally unique identifier (GUID) data.

You can use the DataType enum to specify the data type for your dynamic query conditions, making it easier to work with different types of data, including GUIDs.

Operator

The Operator enum offers a comprehensive set of logical comparison operators for constructing dynamic queries. It now includes both case-sensitive and case-insensitive versions of certain operators, allowing for greater flexibility in query construction. The operators are:

  • Equal: Equality comparison.
  • IEqual: Case-insensitive equality comparison.
  • NotEqual: Inequality comparison.
  • INotEqual: Case-insensitive inequality comparison.
  • GreaterThan: Greater than comparison.
  • GreaterThanOrEqual: Greater than or equal to comparison.
  • LessThan: Less than comparison.
  • LessThanOrEqual: Less than or equal to comparison.
  • Contains: Substring containment check.
  • IContains: Case-insensitive substring containment check.
  • NotContains: Negation of substring containment check.
  • INotContains: Negation of case-insensitive substring containment check.
  • StartsWith: Prefix check.
  • IStartsWith: Case-insensitive prefix check.
  • NotStartsWith: Negation of prefix check.
  • INotStartsWith: Negation of case-insensitive prefix check.
  • EndsWith: Suffix check.
  • IEndsWith: Case-insensitive suffix check.
  • NotEndsWith: Negation of suffix check.
  • INotEndsWith: Negation of case-insensitive suffix check.
  • In: Membership check.
  • IIn: Case-insensitive membership check.
  • NotIn: Negation of membership check.
  • INotIn: Negation of case-insensitive membership check.
  • Between: Range comparison.
  • NotBetween: Negation of range comparison.
  • IsNull: Null check.
  • IsNotNull: Negation of null check.

These operators can be used in combination with the library's extension methods to create complex dynamic queries with both case-sensitive and case-insensitive comparisons, providing greater flexibility in query construction.

Connector

The Connector enum provides logical connectors that allow you to combine conditions within a query. It includes the following connectors:

  • And: Represents the logical "AND" connector.
  • Or: Represents the logical "OR" connector.

You can use these connectors to specify how conditions should be combined in your dynamic queries, enabling flexible query construction.

Intersection

The Intersection enum is used to define how multiple sets of conditions should be combined in a query. It includes the following intersection types:

  • Union: Represents the union of sets, combining conditions with "OR" logic.
  • Intersect: Represents the intersection of sets, combining conditions with "AND" logic.
  • Except: Represents the difference between sets, excluding conditions that meet specified criteria.

These intersection types are valuable when you need to apply logical operations to multiple sets of conditions in your dynamic queries.

Direction

The Direction enum is used to specify the sorting direction in queries. It includes the following sorting directions:

  • Ascending: Represents ascending sorting direction.
  • Descending: Represents descending sorting direction.

You can use the Direction enum when defining sorting preferences for your queries to control whether the results should be sorted in ascending or descending order.


Classes

The DynamicWhere.ex library includes the following classes that enable you to construct dynamic queries:

Condition

The Condition class represents an individual condition in a dynamic query. It contains the following properties:

  • Sort: An integer that specifies the sort order of the condition.
  • Field: A string that indicates the field or property to which the condition applies.
  • DataType: An instance of the DataType enum, specifying the data type of the condition.
  • Operator: An instance of the Operator enum, defining the logical comparison operator for the condition.
  • Values: A list of strings representing the values to compare against. This list may contain one or more values, depending on the operator.

You can create instances of the Condition class to define individual conditions within your dynamic queries.

ConditionGroup

The ConditionGroup class represents a group of conditions that are logically combined within a dynamic query. It includes the following properties:

  • Sort: An integer that determines the sort order of the condition group.
  • Connector: An instance of the Connector enum, specifying how conditions within the group should be connected (using "AND" or "OR" logic).
  • Conditions: A list of Condition objects representing the conditions within the group.
  • SubConditionGroups: A list of ConditionGroup objects, allowing for nested groups of conditions.

You can use the ConditionGroup class to create complex conditions by combining multiple conditions and nesting groups as needed.

ConditionSet

The ConditionSet class represents a set of conditions in a dynamic query. It includes the following properties:

  • Sort: An integer that defines the sort order of the condition set.
  • Intersection: An instance of the Intersection enum, indicating how conditions within the set should be combined (union, intersection, or exclusion).
  • ConditionGroup: An instance of the ConditionGroup class representing the group of conditions within the set.

You can use the ConditionSet class to create sets of conditions and specify how those conditions should be combined within your dynamic queries.

Segment

The Segment class serves as the top-level container for dynamic queries. It includes the following properties:

  • ConditionSets: A list of ConditionSet objects representing multiple sets of conditions within a query.

  • Page: An optional PageBy object containing properties PageNumber and PageSize, allowing you to specify pagination settings for the query.

You can use the Segment class to organize and manage multiple sets of conditions and optionally define pagination settings in your dynamic queries.

OrderBy

The OrderBy class is used to configure sorting in dynamic queries. It includes the following properties:

  • Sort: An integer representing the sort order.
  • Field: A string indicating the field or property by which to sort the query results.
  • Direction: An instance of the Direction enum, specifying the sorting direction, which can be either ascending or descending. The default direction is ascending.

You can use the OrderBy class to specify how the query results should be sorted based on the chosen field and sorting direction. It plays a crucial role in customizing the order of your dynamic query results.

By utilizing the OrderBy class in your dynamic queries, you can achieve precise control over the sorting behavior, ensuring that the results are organized according to your requirements.

PageBy

The PageBy class is used to configure pagination settings for dynamic queries. It includes the following properties:

  • PageNumber: An integer representing the desired page number.
  • PageSize: An integer indicating the number of items to display per page.

By utilizing the PageBy class in your dynamic queries, you can control the pagination behavior, specifying which page of results to retrieve and how many items should be displayed on each page. This is essential for managing large sets of data and presenting it to users in a user-friendly manner.

Filter

The Filter class serves as a configuration container for dynamic queries. It encompasses the following components:

  • ConditionGroup (nullable): Represents a condition group that contains a list of conditions and a logical operator. This allows you to create complex queries with multiple conditions. If set to null, it will not affect the query.
  • Orders (nullable): A list of order-by criteria that specify how the query results should be sorted. If set to null, it will not affect the query's sorting.
  • Page (nullable): Pagination settings that determine the page number and the number of items to display per page. If set to null, it will not affect the query's pagination.

By utilizing the Filter class, you can conveniently define conditions, sorting rules, and pagination settings for your dynamic queries. This flexibility allows you to create dynamic queries tailored to your specific requirements, and it accommodates scenarios where you may not need to specify certain filtering, sorting, or pagination criteria.

These classes provide a powerful foundation for constructing dynamic queries using the DynamicWhere.ex library, offering fine-grained control over your data retrieval and presentation.


Extension Methods

The DynamicWhere.ex library includes a set of extension methods that enhance the functionality of LINQ queries for dynamic querying purposes. Below are the public extension methods provided by the library:

ToListAsync<T>(this IQueryable<T> query, Segment segment)

This extension method allows you to execute an asynchronous query and return the results as a list based on the specified segment of conditions.

Usage:

// Assuming you have an IQueryable<T> query and a Segment segment defined
List<T> results = await query.ToListAsync(segment);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to execute the dynamic query on.
    • segment (Segment): The segment object containing sets of conditions for dynamic querying. It may also contain pagination settings.
  • Return Value:

    • List<T>: A list of query results that meet the conditions specified in the segment, considering any pagination settings if provided.

Where<T>(this IQueryable<T> query, ConditionGroup group)

This extension method allows you to filter an IQueryable based on a specified ConditionGroup.

Usage:

// Assuming you have an IQueryable<T> query and a ConditionGroup conditionGroup defined
var filteredQuery = query.Where(conditionGroup);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to filter.
    • conditionGroup (ConditionGroup): The condition group specifying the filtering conditions.
  • Return Value:

    • IQueryable<T>: A new queryable instance with the specified conditions applied.

Where<T>(this IQueryable<T> query, Condition condition)

This extension method allows you to filter an IQueryable based on a single Condition.

Usage:

// Assuming you have an IQueryable<T> query and a Condition condition defined
var filteredQuery = query.Where(condition);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to filter.
    • condition (Condition): The single condition specifying the filtering criteria.
  • Return Value:

    • IQueryable<T>: A new queryable instance with the specified condition applied.

These extension methods empower you to build dynamic queries by composing conditions and filter your data based on flexible criteria.


Additional Extension Methods

Page<T>(this IQueryable<T> query, PageBy page)

This extension method allows you to apply pagination to an IQueryable, specifying the page number and page size.

Usage:

// Assuming you have an IQueryable<T> query and a PageBy page defined
var pagedQuery = query.Page(page);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to apply pagination to.
    • page (PageBy): The page object specifying the page number and page size.
  • Return Value:

    • IQueryable<T>: A new queryable instance with pagination applied.

Order<T>(this IQueryable<T> query, OrderBy order)

This extension method allows you to order the results of an IQueryable based on a specified OrderBy configuration.

Usage:

// Assuming you have an IQueryable<T> query and an OrderBy order defined
var orderedQuery = query.Order(order);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to order.
    • order (OrderBy): The order-by configuration specifying the field and sorting direction.
  • Return Value:

    • IQueryable<T>: A new queryable instance with the specified ordering applied.

Order<T>(this IQueryable<T> query, List<OrderBy> orders)

This extension method allows you to order the results of an IQueryable based on a list of OrderBy configurations.

Usage:

// Assuming you have an IQueryable<T> query and a List<OrderBy> orders defined
var orderedQuery = query.Order(orders);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to order.
    • orders (List<OrderBy>): A list of order-by configurations specifying the fields and sorting directions.
  • Return Value:

    • IQueryable<T>: A new queryable instance with the specified ordering applied.

Filter<T>(this IQueryable<T> query, Filter filter)

This extension method allows you to filter an IQueryable based on a Filter configuration, including conditions, sorting, and pagination.

Usage:

// Assuming you have an IQueryable<T> query and a Filter filter defined
var filteredQuery = query.Filter(filter);

Documentation:

  • Parameters:

    • query (IQueryable<T>): The queryable source to filter.
    • filter (Filter): The filter configuration specifying conditions, sorting, and pagination.
  • Return Value:

    • IQueryable<T>: A new queryable instance with the specified filtering, ordering, and pagination applied.

These additional extension methods extend your capabilities to filter, order, and paginate data within your dynamic queries for more comprehensive data manipulation.

JSON Examples

Condition

  • Condition with a single value
{
  "Sort": 1,
  "Field": "ProductName",
  "DataType": "Text",
  "Operator": "Equal",
  "Values": ["apple"]
}

Condition Group

  • Condition Group with 3 Conditions and 2 Subgroups
  • Each Subgroup with 2 Conditions
{
  "Sort": 1,
  "Connector": "And",
  "Conditions": [
    {
      "Sort": 1,
      "Field": "Price",
      "DataType": "Number",
      "Operator": "GreaterThan",
      "Values": ["10"]
    },
    {
      "Sort": 2,
      "Field": "Category",
      "DataType": "Text",
      "Operator": "Equal",
      "Values": ["Electronics"]
    },
    {
      "Sort": 3,
      "Field": "InStock",
      "DataType": "Boolean",
      "Operator": "Equal",
      "Values": ["true"]
    }
  ],
  "SubConditionGroups": [
    {
      "Sort": 1,
      "Connector": "Or",
      "Conditions": [
        {
          "Sort": 1,
          "Field": "Discount",
          "DataType": "Number",
          "Operator": "GreaterThan",
          "Values": ["20"]
        },
        {
          "Sort": 2,
          "Field": "Brand",
          "DataType": "Text",
          "Operator": "Equal",
          "Values": ["Sony"]
        }
      ],
      "SubConditionGroups": []
    },
    {
      "Sort": 2,
      "Connector": "And",
      "Conditions": [
        {
          "Sort": 1,
          "Field": "ShippingDate",
          "DataType": "DateTime",
          "Operator": "GreaterThan",
          "Values": ["2023-01-01"]
        },
        {
          "Sort": 2,
          "Field": "ShippingDate",
          "DataType": "DateTime",
          "Operator": "LessThanOrEqual",
          "Values": ["2023-12-31"]
        }
      ],
      "SubConditionGroups": []
    }
  ]
}

Segment

  • Segment with 2 Sets
  • Each Set with a Condition Group
  • Each Condition Group with 3 Conditions and 2 Subgroups
  • Each Subgroup with 2 Conditions
  • Pagination Setting
{
  "ConditionSets": [
    {
      "Sort": 1,
      "Intersection": "Union",
      "ConditionGroup": {
        "Sort": 1,
        "Connector": "Or",
        "Conditions": [
          {
            "Sort": 1,
            "Field": "Rating",
            "DataType": "Number",
            "Operator": "GreaterThan",
            "Values": ["4.5"]
          },
          {
            "Sort": 2,
            "Field": "Reviews",
            "DataType": "Number",
            "Operator": "GreaterThan",
            "Values": ["100"]
          },
          {
            "Sort": 3,
            "Field": "Discount",
            "DataType": "Number",
            "Operator": "GreaterThan",
            "Values": ["30"]
          }
        ],
        "SubConditionGroups": [
          {
            "Sort": 1,
            "Connector": "Or",
            "Conditions": [
              {
                "Sort": 1,
                "Field": "Brand",
                "DataType": "Text",
                "Operator": "Equal",
                "Values": ["Samsung"]
              },
              {
                "Sort": 2,
                "Field": "Brand",
                "DataType": "Text",
                "Operator": "Equal",
                "Values": ["LG"]
              }
            ],
            "SubConditionGroups": []
          },
          {
            "Sort": 2,
            "Connector": "And",
            "Conditions": [
              {
                "Sort": 1,
                "Field": "InStock",
                "DataType": "Boolean",
                "Operator": "Equal",
                "Values": ["true"]
              },
              {
                "Sort": 2,
                "Field": "Category",
                "DataType": "Text",
                "Operator": "Equal",
                "Values": ["Appliances"]
              }
            ],
            "SubConditionGroups": []
          }
        ]
      }
    },
    {
      "Sort": 2,
      "Intersection": "Intersect",
      "ConditionGroup": {
        "Sort": 1,
        "Connector": "And",
        "Conditions": [
          {
            "Sort": 1,
            "Field": "Color",
            "DataType": "Text",
            "Operator": "Equal",
            "Values": ["Red"]
          },
          {
            "Sort": 2,
            "Field": "Size",
            "DataType": "Text",
            "Operator": "Equal",
            "Values": ["Large"]
          },
          {
            "Sort": 3,
            "Field": "Weight",
            "DataType": "Number",
            "Operator": "LessThanOrEqual",
            "Values": ["5"]
          }
        ],
        "SubConditionGroups": [
          {
            "Sort": 1,
            "Connector": "Or",
            "Conditions": [
              {
                "Sort": 1,
                "Field": "Price",
                "DataType": "Number",
                "Operator": "LessThanOrEqual",
                "Values": ["50"]
              },
              {
                "Sort": 2,
                "Field": "Rating",
                "DataType": "Number",
                "Operator": "GreaterThan",
                "Values": ["4"]
              }
            ],
            "SubConditionGroups": []
          },
          {
            "Sort": 2,
            "Connector": "And",
            "Conditions": [
              {
                "Sort": 1,
                "Field": "Category",
                "DataType": "Text",
                "Operator": "Equal",
                "Values": ["Clothing"]
              },
              {
                "Sort": 2,
                "Field": "Season",
                "DataType": "Text",
                "Operator": "Equal",
                "Values": ["Summer"]
              }
            ],
            "SubConditionGroups": []
          }
        ]
      }
    }
  ],
  "Page": {
    "PageNumber": 2,
    "PageSize": 10
  }
}

These JSON examples demonstrate various scenarios of conditions, condition groups, and segments that can be used with the library.

PageBy

In this example, we specify that we want to retrieve the second page of data, with each page containing 10 items.

{
  "PageNumber": 2,
  "PageSize": 10
}

OrderBy

This JSON example represents an ordering configuration where we want to sort the data by the "ProductName" field in ascending order.

{
  "Sort": 1,
  "Field": "ProductName",
  "Direction": "Ascending"
}

Filter

This JSON example represents a filter configuration with the following components:

  • ConditionGroup: A set of conditions combined using the "And" logical operator.
    • Condition 1: Filter products in the "Electronics" category.
    • Condition 2: Filter products with a price greater than 100.
  • Orders: Specifies the ordering criteria.
    • Order 1: Sort products by "ProductName" in ascending order.
    • Order 2: Then sort products by "Price" in descending order.
  • Page: Specifies that we want the first page of results with a page size of 20 items.
{
  "ConditionGroup": {
    "Connector": "And",
    "Conditions": [
      {
        "Sort": 1,
        "Field": "Category",
        "DataType": "Text",
        "Operator": "Equal",
        "Values": ["Electronics"]
      },
      {
        "Sort": 2,
        "Field": "Price",
        "DataType": "Number",
        "Operator": "GreaterThan",
        "Values": ["100"]
      }
    ]
  },
  "Orders": [
    {
      "Sort": 1,
      "Field": "ProductName",
      "Direction": "Ascending"
    },
    {
      "Sort": 2,
      "Field": "Price",
      "Direction": "Descending"
    }
  ],
  "Page": {
    "PageNumber": 1,
    "PageSize": 20
  }
}

These JSON examples demonstrate how you can configure PageBy, OrderBy, and Filter settings for dynamic querying of data.

License

This library is released under a free and open-source license, allowing you to use it in your projects without restrictions.

Change Log

All notable changes to the DynamicWhere.ex library will be documented in this section.

[v1.4.3] - 2023-09-22

Added
  • Optional pagination feature to the Segment class:

    You can now include a "Page" object within the Segment to specify pagination settings, such as "PageNumber" and "PageSize". This allows for more fine-grained control over the results returned by dynamic queries.

    Pagination settings applied at the Segment level ensure that the pagination is performed on the final result set, providing you with precise control over how the entire query result is paginated.

[v1.4.1] - 2023-09-18

Enhanced Flexibility
  • The Filter configuration in dynamic queries has been improved for greater flexibility.
  • ConditionGroup, Orders, and Page objects are now nullable within the Filter class.
  • This change allows you to use any combination of ConditionGroup, Orders, or Page based on your specific query requirements.
  • If any of these objects are set to null, they will not impact the query, providing more adaptable and versatile query configurations.

[v1.4.0] - 2023-09-14

Added
  • Added support for pagination, allowing users to specify page numbers and page sizes using the PageBy class.
  • Implemented the ability to define sorting criteria using the OrderBy class.
  • Introduced the Filter class, enabling users to configure complex dynamic queries.

[v1.3.0] - 2023-09-13

Refactored
  • Refactored and improved codebase for better maintainability.
  • Added comprehensive documentation, summaries, and comments to enhance code readability.
  • Introduced meaningful names and structuring to make code cleaner and more understandable.

[v1.2.0] - 2023-09-12

Added
  • Added support for the GUID data type, allowing filtering and comparisons using GUID values.
  • Enabled case-insensitive comparisons for text data types.
  • Introduced the ability to specify nested property names in conditions.

[v1.0.0] - 2023-09-11

Initial Release
  • The DynamicWhere.ex library is released, providing dynamic querying capabilities for LINQ queries.

Credits

This extension is built upon the foundation of System.Linq.Dynamic.Core, and we extend our appreciation to the authors and contributors of the original library for their valuable work.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.8.4 91 10/12/2024
1.8.3 93 8/8/2024
1.8.2 84 7/10/2024
1.8.1 527 3/29/2024
1.8.0 209 2/11/2024
1.7.2 120 2/9/2024
1.7.1 108 2/8/2024
1.7.0 286 11/5/2023
1.6.0 187 9/30/2023
1.5.3 176 9/25/2023
1.5.2 182 9/24/2023
1.5.1 156 9/23/2023
1.5.0 140 9/22/2023
1.4.3 148 9/21/2023
1.4.2 155 9/19/2023
1.4.1 164 9/18/2023
1.4.0 163 9/14/2023
1.3.0 149 9/13/2023
1.2.0 174 9/12/2023
1.0.2 197 9/11/2023
1.0.1 177 9/11/2023
1.0.0 181 9/11/2023