protected virtual void ApplySorting <TSource>() { if (Criteria.Sorts?.Any() != true) { ApplyNoSortInterceptor <TSource>(); return; } bool isAppending = false; Criteria.Sorts.ForEach(sort => { var transformedSort = InterceptSort <TSource>(sort); if (transformedSort.Count == 0) { return; } transformedSort.ForEach(ts => { CurrentQueryable = CurrentQueryable.OrderBy(ts.Path, ts.Ascending == false ? QueryOrderByDirection.Descending : QueryOrderByDirection.Ascending, isAppending); isAppending = true; }); }); }
public TResult Execute <TResult>(Expression expression) { var objectQuery = CurrentQueryable.GetObjectQuery(); // GET provider var objectQueryProviderProperty = objectQuery.GetType().GetProperty("ObjectQueryProvider", BindingFlags.NonPublic | BindingFlags.Instance); var provider = (IQueryProvider)objectQueryProviderProperty.GetValue(objectQuery); // CREATE query from the expression var createQueryMethod = provider.GetType().GetMethod("CreateQuery", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(Expression) }, null); createQueryMethod = createQueryMethod.MakeGenericMethod(typeof(TResult)); var query = createQueryMethod.Invoke(provider, new object[] { expression }); var orderedQuery = query as IOrderedQueryable <TResult>; var queryNew = CurrentQueryable.CreateOrderedQueryable(orderedQuery, false); // EXECUTE the batch queryNew.OwnerBatch.Execute(); // SET result as single value // todo: make something about first or default... queryNew.Result = ((IEnumerable <TResult>)queryNew.Result).FirstOrDefault(); return((TResult)queryNew.Result); }
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 void ApplyFilters <TSource>() { if (true != Criteria.Filters?.Any()) { return; } CurrentQueryable = CurrentQueryable.Query(whereBuilder => { Criteria.Filters.ForEach(filter => ApplyFilter <TSource>(whereBuilder, filter)); }); }
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>(); // 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. var 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); }
protected virtual IQueryExecutionResult ExecuteGrouping <T>() { var result = new QueryExecutionResult(); // 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 <T>(g)).ToList(); // get the aggregates. var aggregateResults = FetchAggregates <T>(finalGroups); // sorting. finalGroups.ForEach(fg => Criteria.Sorts.Insert(0, new Sort(fg.Path, fg.Ascending))); // apply sorting and paging. ApplySorting <T>(); ApplyPaging <T>(); // 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. // var groupRecords = CurrentQueryable.ToDynamicClassList(); // now join them into logical collections // result.Data = RecursiveRegroup<T>(groupRecords, aggregateResults, Criteria.Groups.First()); result.Data = CurrentQueryable; result.Aggregates = CalculateTotalAggregate <T>(CurrentQueryable); return(result); }
/// <summary>Executes the given expression.</summary> /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception> /// <typeparam name="TResult">Type of the result.</typeparam> /// <param name="expression">The expression.</param> /// <returns>A TResult.</returns> public TResult Execute <TResult>(Expression expression) { var methodCall = expression as MethodCallExpression; if (methodCall == null) { throw new Exception(ExceptionMessage.GeneralException); } if (methodCall.Arguments.Count > 1 && methodCall.Arguments.Any(x => x.Type.IsSubclassOf(typeof(Expression)))) { throw new Exception(ExceptionMessage.QueryIncludeQuery_ArgumentExpression); } // CREATE the new query by selecting included entities in an anonymous type var newQuery = CurrentQueryable.CreateQueryable(); // CREATE a new immediate method from the immediate method used by the user var newImmediateMethod = methodCall.Method.GetGenericMethodDefinition().MakeGenericMethod(newQuery.ElementType); // REPLACE the first argument with the new query expression var arguments = methodCall.Arguments.ToList(); arguments[0] = newQuery.Expression; // CREATE the new expression var newExpression = Expression.Call(null, newImmediateMethod, arguments); // EXECUTE the new expression var value = OriginalProvider.Execute(newExpression); // CHECK if a value has been returned if (value == null) { return((TResult)(object)null); } // GET the value from the anonymous type return((TResult)value.GetType().GetProperty("x").GetValue(value, null)); }
protected virtual IQueryable CreateFetchAggregateSelectExpression <TSource>(IGroup finalGroup, List <IGroup> previousGroups) { var groupExpression = CurrentQueryable.GroupBy(QueryableUnderlyingType, gb => { var groupKeyIndex = -1; previousGroups.ForEach(pg => gb.Path(pg.Path, $"Key_{++groupKeyIndex}")); gb.Path(finalGroup.Path, $"Key_{++groupKeyIndex}"); }); var selectExpression = groupExpression.Select(sb => { var groupKeyIndex = -1; previousGroups.ForEach(pg => sb.Key($"Key_{++groupKeyIndex}", $"Key_{groupKeyIndex}")); sb.Key($"Key_{++groupKeyIndex}", $"Key_{groupKeyIndex}"); Criteria.Aggregates.ForEach((a, ai) => { var fa = InterceptAggregate <TSource>(a); var selectType = ResolveSelectFrom(fa.Type); sb.Aggregate(fa.Path, selectType, $"Agg_{ai}"); }); }); return(selectExpression); }
/// <summary>Executes the asynchronous operation.</summary> /// <param name="expression">The expression.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A Task<object></returns> public Task <object> ExecuteAsync(Expression expression, CancellationToken cancellationToken) { expression = CurrentQueryable.Visit(expression); return(OriginalProvider.ExecuteAsync(expression, cancellationToken)); }
/// <summary>Executes the given expression.</summary> /// <typeparam name="TResult">Type of the result.</typeparam> /// <param name="expression">The expression to execute.</param> /// <returns>The object returned by the execution of the expression.</returns> public TResult Execute <TResult>(Expression expression) { expression = CurrentQueryable.Visit(expression); return(OriginalProvider.Execute <TResult>(expression)); }
/// <summary>Executes the given expression.</summary> /// <param name="expression">The expression to execute.</param> /// <returns>The object returned by the execution of the expression.</returns> public object Execute(Expression expression) { expression = CurrentQueryable.Visit(expression); return(OriginalProvider.Execute(expression)); }
public IQueryable <TElement> CreateQuery <TElement>(Expression expression) { var query = OriginalProvider.CreateQuery <TElement>(expression); return(CurrentQueryable.CreateOrderedQueryable(query as IOrderedQueryable <TElement>)); }