DynamicWhere.ex
DynamicWhere.exv3.4.0·docs

.Group<T>(groupBy)

Groups the query by the specified fields and applies aggregations. Returns a dynamic IQueryable whose elements expose the group-by fields and aggregate aliases as properties.

Guarded, small groups are dropped by default
DwCaps.MinGroupSize ships on, at 5, so a guarded call removes every group with fewer than five rows — not refused, and nothing in the answer says a group was dropped. That is right for anonymised reporting and surprising for an operational count. Set Caps.MinGroupSize = 1 to switch the floor off, deliberately. An unguarded call is never floored. See k-anonymity.

Signature

public static IQueryable Group<T>(this IQueryable<T> query, GroupBy groupBy)
    where T : class
ParameterTypeDescription
groupByGroupByGrouping and aggregation config

Validations

  • Must have at least one field — GroupByMustHaveFields.
  • Fields must be unique (case-insensitive) — GroupByFieldsMustBeUnique.
  • Fields cannot be complex/navigation types — GroupByFieldCannotBeComplexType.
  • Fields cannot be a collection of collections — GroupByFieldCannotBeCollectionType. A path ending on a collection is checked by its element type, so a collection of entities fails the rule above and a List<string> passes.
  • Aggregation alias must be an identifier — a letter or _, then letters, digits or _. Spaces, dots, hyphens and a leading digit all fail — InvalidAlias.
  • Aggregation aliases must be unique — AggregationAliasesMustBeUnique.
  • Aggregation alias cannot match a GroupBy field — AggregationAliasCannotBeGroupByField({alias}).
  • Aggregation field must be a simple type — AggregationFieldMustBeSimpleType.
  • Aggregation field cannot be a collection of collections — AggregationFieldCannotBeCollectionType. As for a group field, a collection is checked by its element type.
  • Sumation / Average only work on numeric fields — UnsupportedAggregatorForType.
  • Minimum / Maximum do not work on Boolean — UnsupportedAggregatorForType.
Warning
Dotted GroupBy fields (e.g., Category.Name) produce flattened alias keys in the dynamic result objects (e.g., CategoryName). Order fields in Summary.Orders should use the dotted form; the library handles alias mapping internally.

Returns

IQueryable — a dynamic query with grouped results. Each element exposes the group-by fields (flattened to alias keys) and the aggregation aliases.

Example

var groupBy = new GroupBy
{
    Fields = new List<string> { "Category.Name" },
    AggregateBy = new List<AggregateBy>
    {
        new AggregateBy { Field = null,    Alias = "TotalCount", Aggregator = Aggregator.Count },
        new AggregateBy { Field = "Price", Alias = "AvgPrice",   Aggregator = Aggregator.Average },
        new AggregateBy { Field = "Price", Alias = "MaxPrice",   Aggregator = Aggregator.Maximum }
    }
};

var grouped = dbContext.Products.Group(groupBy);
{
  "fields": ["Category.Name"],
  "aggregateBy": [
    { "field": null,    "alias": "TotalCount", "aggregator": "Count" },
    { "field": "Price", "alias": "AvgPrice",   "aggregator": "Average" },
    { "field": "Price", "alias": "MaxPrice",   "aggregator": "Maximum" }
  ]
}

See also