DynamicWhere.ex
DynamicWhere.exv2.1.0·docs

.ToListAsync<T>(Segment)

Async-only segment operation. Executes each ConditionSet independently, then applies set operations (Union / Intersect / Except), followed by ordering and pagination.

Warning
Async-only. .ToListAsync<T>(Segment) is the only entry point for segment queries — there is no synchronous .ToList<T>(Segment) variant. Each ConditionSet is materialized independently into memory, then set operations are performed in-memory.

Signature

public static Task<SegmentResult<T>> ToListAsync<T>(
    this IQueryable<T> query,
    Segment segment)
    where T : class, new()
ParameterTypeDescription
segmentSegmentComposition object — ConditionSets, Selects, Orders, Page

Pipeline

  • For each ConditionSet (in Sort order): apply its ConditionGroup as a Where, then materialize that set into memory.
  • Apply set operations between consecutive results using the next set's Intersection (Union, Intersect, or Except). The first set's Intersection is ignored.
  • Apply Orders on the combined in-memory result.
  • Apply Page on the combined in-memory result.
  • Optionally project via Selects before returning.

Validations

  • ConditionSets Sort values must be unique — SetsUniqueSort.
  • Sets at index 1+ must have Intersection specified — RequiredIntersection.
  • Each ConditionSet.ConditionGroup is validated as in .Where<T>.
  • Orders (if provided): each Field must be non-empty and valid on T.
  • Page (if provided): both PageNumber and PageSize must be > 0.

Returns

Task<SegmentResult<T>> — inherits all properties from FilterResult<T>.

Example

var segment = new Segment
{
    ConditionSets = new List<ConditionSet>
    {
        new ConditionSet
        {
            Sort = 1,
            Intersection = null,
            ConditionGroup = new ConditionGroup
            {
                Connector = Connector.And,
                Conditions = new List<Condition>
                {
                    new Condition { Sort = 1, Field = "Category.Name", DataType = DataType.Text, Operator = Operator.Equal, Values = new List<object> { "Electronics" } }
                }
            }
        },
        new ConditionSet
        {
            Sort = 2,
            Intersection = Intersection.Union,
            ConditionGroup = new ConditionGroup
            {
                Connector = Connector.And,
                Conditions = new List<Condition>
                {
                    new Condition { Sort = 1, Field = "Price", DataType = DataType.Number, Operator = Operator.LessThan, Values = new List<object> { 20 } }
                }
            }
        },
        new ConditionSet
        {
            Sort = 3,
            Intersection = Intersection.Except,
            ConditionGroup = 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> { false } }
                }
            }
        }
    },
    Selects = new List<string> { "Id", "Name", "Price" },
    Orders  = new List<OrderBy> { new OrderBy { Sort = 1, Field = "Name", Direction = Direction.Ascending } },
    Page    = new PageBy { PageNumber = 1, PageSize = 20 }
};

SegmentResult<Product> result = await dbContext.Products.ToListAsync(segment);
{
  "conditionSets": [
    {
      "sort": 1,
      "intersection": null,
      "conditionGroup": {
        "connector": "And",
        "conditions": [
          { "sort": 1, "field": "Category.Name", "dataType": "Text", "operator": "Equal", "values": ["Electronics"] }
        ],
        "subConditionGroups": []
      }
    },
    {
      "sort": 2,
      "intersection": "Union",
      "conditionGroup": {
        "connector": "And",
        "conditions": [
          { "sort": 1, "field": "Price", "dataType": "Number", "operator": "LessThan", "values": ["20"] }
        ],
        "subConditionGroups": []
      }
    },
    {
      "sort": 3,
      "intersection": "Except",
      "conditionGroup": {
        "connector": "And",
        "conditions": [
          { "sort": 1, "field": "IsActive", "dataType": "Boolean", "operator": "Equal", "values": ["false"] }
        ],
        "subConditionGroups": []
      }
    }
  ],
  "selects": ["Id", "Name", "Price"],
  "orders": [
    { "sort": 1, "field": "Name", "direction": "Ascending" }
  ],
  "page": { "pageNumber": 1, "pageSize": 20 }
}

Logic: (Electronics) UNION (Price < 20) EXCEPT (Inactive) → order → paginate.

{
  "pageNumber": 1,
  "pageSize": 20,
  "pageCount": 2,
  "totalCount": 35,
  "data": [
    { "id": 1, "name": "Adapter Cable", "price": 9.99 }
  ],
  "queryString": null
}

See also