DynamicWhere.ex
DynamicWhere.exv3.4.0·docs

Segment

A Segment stitches together multiple ConditionSet objects with Union / Intersect / Except set operations, then applies optional sort and pagination. A projection, if you give one, is applied after they are combined, to the ordered and paged rows.

Properties

PropertyTypeDescription
ConditionSetsList<ConditionSet>Ordered condition sets.
SelectsList<string>?Optional field projection, applied last to the combined, ordered and paged rows, as for a Filter.
OrdersList<OrderBy>?Optional sort criteria.
PagePageBy?Optional pagination.
Async-only
The condition sets are combined into one query that the database answers: Union and Intersect join the sets' conditions, and Except removes its set's rows by primary key. A type with no primary key uses SQL UNION / INTERSECT / EXCEPT. Segments are executed exclusively through ToListAsync<T>(Segment). There is no synchronous counterpart.

C# example

var segment = new Segment
{
    ConditionSets = new List<ConditionSet>
    {
        new ConditionSet
        {
            Sort = 0,
            ConditionGroup = new ConditionGroup
            {
                Connector = Connector.And,
                Conditions = new List<Condition>
                {
                    new Condition
                    {
                        Sort = 1, Field = "Country",
                        DataType = DataType.Text, Operator = Operator.Equal,
                        Values = new List<object> { "IQ" }
                    }
                }
            }
        },
        new ConditionSet
        {
            Sort = 1,
            Intersection = Intersection.Except,
            ConditionGroup = new ConditionGroup
            {
                Connector = Connector.And,
                Conditions = new List<Condition>
                {
                    new Condition
                    {
                        Sort = 1, Field = "IsBlocked",
                        DataType = DataType.Boolean, Operator = Operator.Equal,
                        Values = new List<object> { true }
                    }
                }
            }
        }
    },
    Orders = new List<OrderBy>
    {
        new OrderBy { Sort = 1, Field = "Name" }
    },
    Page = new PageBy { PageNumber = 1, PageSize = 50 }
};

SegmentResult<Customer> result = await dbContext.Customers.ToListAsync(segment);

JSON example

{
  "conditionSets": [
    {
      "sort": 0,
      "intersection": null,
      "conditionGroup": {
        "connector": "And",
        "conditions": [
          { "sort": 1, "field": "Country", "dataType": "Text", "operator": "Equal", "values": ["IQ"] }
        ],
        "subConditionGroups": []
      }
    },
    {
      "sort": 1,
      "intersection": "Except",
      "conditionGroup": {
        "connector": "And",
        "conditions": [
          { "sort": 1, "field": "IsBlocked", "dataType": "Boolean", "operator": "Equal", "values": [true] }
        ],
        "subConditionGroups": []
      }
    }
  ],
  "orders": [
    { "sort": 1, "field": "Name", "direction": "Ascending" }
  ],
  "page": { "pageNumber": 1, "pageSize": 50 }
}

Clone

Segment.Clone() is public since 3.3.0. It returns a deep copy — every condition set with its own condition group, the Selects list, each order and the page — so nothing either request is given afterwards reaches the other.

Every node is new. The values a condition carries stay the caller's own objects, in a new list: they are scalars decoded from JSON and nothing in the pipeline writes to them.

Segment page2 = caller.Clone();
page2.Page!.PageNumber = 2;          // the caller's own segment is untouched

Reading one request again with a part changed, the next page or another order, used to mean rebuilding it around the caller's own clauses, which leaves both requests holding one condition tree: a rewrite of either reaches both. The library has cloned before rewriting anything since 3.0; callers could not until now. A branch the caller left null stays null, and a null entry inside a list is copied as a null entry rather than failing on it (3.3.0), so the refusal belongs to the method that runs the request and reads the same for a copy.

See also