DynamicWhere.ex
DynamicWhere.exv2.1.0·docs

.Where<T>(...)

Apply a single Condition or a full ConditionGroup (with optional nested sub-groups joined by And / Or) to a query.

Single condition overload

public static IQueryable<T> Where<T>(this IQueryable<T> query, Condition condition)
    where T : class
ParameterTypeDescription
conditionConditionThe filter condition

Returns: IQueryable<T> — filtered query.

Condition-group overload

public static IQueryable<T> Where<T>(this IQueryable<T> query, ConditionGroup group)
    where T : class
ParameterTypeDescription
groupConditionGroupThe filter group — flat Conditions plus optional nested SubConditionGroups

Returns: IQueryable<T> — filtered query.

Validations

Condition validation (applied per condition):

  • Field must be non-empty and exist on T (case-insensitive, auto-normalized) — error code InvalidField.
  • Between / NotBetween require exactly 2 values — RequiredTwoValue.
  • In / IIn / NotIn / INotIn require 1+ values — RequiredValues.
  • IsNull / IsNotNull require 0 values — NotRequiredValues.
  • All other operators require exactly 1 value — RequiredOneValue({Operator}).
  • Values must not be null/whitespace — InvalidValue.
  • Guid values must parse as Guid InvalidFormat.
  • Number values must parse as a numeric type — InvalidFormat.
  • Boolean values must parse as bool InvalidFormat.
  • Date / DateTime values must parse as DateTimeInvalidFormat.

ConditionGroup validation (applied per group):

  • All Condition.Sort values within the group must be unique — ConditionsUniqueSort.
  • All SubConditionGroups.Sort values must be unique — SubConditionsGroupsUniqueSort.
  • Each child condition is validated individually.
Note
When a condition's Field path traverses a collection property (e.g., Orders.OrderItems.ProductName), the library automatically wraps the inner segment in a .Any() lambda. There is no built-in .All() support.

Example — single condition

var condition = new Condition
{
    Sort = 1,
    Field = "Name",
    DataType = DataType.Text,
    Operator = Operator.IContains,
    Values = new List<object> { "phone" }
};

var query = dbContext.Products.Where(condition);
{
  "sort": 1,
  "field": "Name",
  "dataType": "Text",
  "operator": "IContains",
  "values": ["phone"]
}

Example — condition group with nested OR

var group = new ConditionGroup
{
    Connector = Connector.And,
    Conditions = new List<Condition>
    {
        new Condition
        {
            Sort = 1,
            Field = "IsActive",
            DataType = DataType.Boolean,
            Operator = Operator.Equal,
            Values = new List<object> { true }
        }
    },
    SubConditionGroups = new List<ConditionGroup>
    {
        new ConditionGroup
        {
            Sort = 1,
            Connector = Connector.Or,
            Conditions = new List<Condition>
            {
                new Condition { Sort = 1, Field = "Role", DataType = DataType.Text, Operator = Operator.Equal, Values = new List<object> { "Admin" } },
                new Condition { Sort = 2, Field = "Role", DataType = DataType.Text, Operator = Operator.Equal, Values = new List<object> { "Manager" } }
            }
        }
    }
};

var query = dbContext.Users.Where(group);
{
  "connector": "And",
  "conditions": [
    { "sort": 1, "field": "IsActive", "dataType": "Boolean", "operator": "Equal", "values": ["true"] }
  ],
  "subConditionGroups": [
    {
      "sort": 1,
      "connector": "Or",
      "conditions": [
        { "sort": 1, "field": "Role", "dataType": "Text", "operator": "Equal", "values": ["Admin"] },
        { "sort": 2, "field": "Role", "dataType": "Text", "operator": "Equal", "values": ["Manager"] }
      ],
      "subConditionGroups": []
    }
  ]
}

Equivalent SQL: WHERE IsActive = true AND (Role = 'Admin' OR Role = 'Manager').

See also