protected virtual IQueryExecutionResult <TRecord> ExecuteGrouping <TSource, TRecord>() { var result = new QueryExecutionGroupResult <TRecord>(); // preserve queryable. var queryableAfterFilters = CurrentQueryable; result.TotalRecords = queryableAfterFilters.LongCount(); CalculatePageCount(result); // intercept groups in advance to avoid doing it more than once :) var finalGroups = Criteria.Groups.Select(g => InterceptGroup <TSource>(g)).ToList(); // get the aggregates. var aggregateResults = FetchAggregates <TSource>(finalGroups); // sorting. finalGroups.ReversedForEach(fg => Criteria.Sorts.Insert(0, new Sort(fg.Path, fg.Ascending))); // apply sorting and paging. ApplySorting <TSource>(); ApplyPaging <TSource>(); if (Options.GroupByInMemory) { CurrentQueryable = CurrentQueryable.ToObjectList().Cast <TSource>().AsQueryable(); } CurrentQueryable = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => { gb.NullChecking(Options.GroupByInMemory ? Options.GroupByInMemoryNullCheck : false); finalGroups.ForEach((fg, index) => gb.Path(fg.Path, $"Key_{index}")); }); CurrentQueryable = CurrentQueryable.Select(sb => { sb.NullChecking(Options.GroupByInMemory ? Options.GroupByInMemoryNullCheck : false); finalGroups.ForEach((fg, index) => sb.Key($"Key_{index}", $"Key_{index}")); sb.ToList("Records"); }); // loop through the grouped records. var groupRecords = CurrentQueryable.ToDynamicClassList(); // now join them into logical collections var lastLists = new List <(List <TSource> source, IGroupQueryResult <TRecord> group)>(); result.Groups = RecursiveRegroup <TSource, TRecord>(groupRecords, aggregateResults, Criteria.Groups.First(), lastLists); // intercept grouped by. QueryInterceptToGrouped <TSource, TRecord>(lastLists).Wait(); result.Aggregates = CalculateTotalAggregate <TSource>(queryableAfterFilters); return(result); }
protected virtual async Task <IQueryExecutionResult <TRecord> > ExecuteAsyncGrouping <TSource, TRecord>(CancellationToken cancellationToken) { var result = new QueryExecutionGroupResult <TRecord>(); // preserve queryable. var queryableAfterFilters = CurrentQueryable; // async. result.TotalRecords = await this.AsyncQueryableService.LongCountAsync((IQueryable <TSource>) queryableAfterFilters, cancellationToken); CalculatePageCount(result); // intercept groups in advance to avoid doing it more than once :) var finalGroups = Criteria.Groups.Select(g => InterceptGroup <TSource>(g)).ToList(); // get the aggregates. var aggregateResults = await FetchAggregatesAsync <TSource>(finalGroups, cancellationToken); // sorting. finalGroups.ReversedForEach(fg => Criteria.Sorts.Insert(0, new Sort(fg.Path, fg.Ascending))); // apply sorting and paging. ApplySorting <TSource>(); ApplyPaging <TSource>(); List <DynamicClass> groupRecords; if (Options.GroupByInMemory) { CurrentQueryable = CurrentQueryable.ToObjectList().Cast <TSource>().AsQueryable(); // create group & select expression. CurrentQueryable = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => { gb.NullChecking(Options.GroupByInMemory ? Options.GroupByInMemoryNullCheck : false); finalGroups.ForEach((fg, index) => gb.Path(fg.Path, $"Key_{index}")); }); CurrentQueryable = CurrentQueryable.Select(sb => { sb.NullChecking(Options.GroupByInMemory ? Options.GroupByInMemoryNullCheck : false); finalGroups.ForEach((fg, index) => sb.Key($"Key_{index}", $"Key_{index}")); sb.ToList("Records"); }); // loop through the grouped records. groupRecords = CurrentQueryable.Cast <DynamicClass>().ToList(); } else { // create group & select expression. CurrentQueryable = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => { finalGroups.ForEach((fg, index) => gb.Path(fg.Path, $"Key_{index}")); }); CurrentQueryable = CurrentQueryable.Select(sb => { finalGroups.ForEach((fg, index) => sb.Key($"Key_{index}", $"Key_{index}")); sb.ToList("Records"); }); // loop through the grouped records. groupRecords = await AsyncQueryableService.ToListAsync(CurrentQueryable.Cast <DynamicClass>(), cancellationToken); } // now join them into logical collections var lastLists = new List <(List <TSource> entities, IGroupQueryResult <TRecord> group)>(); result.Groups = RecursiveRegroup <TSource, TRecord>(groupRecords, aggregateResults, Criteria.Groups.First(), lastLists); // converted to grouped by. await QueryInterceptToGrouped <TSource, TRecord>(lastLists); result.Aggregates = await CalculateTotalAggregateAsync <TSource>(queryableAfterFilters, cancellationToken); return(result); }