예제 #1
0
        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;
                });
            });
        }
예제 #2
0
        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);
        }
예제 #4
0
        protected virtual void ApplyFilters <TSource>()
        {
            if (true != Criteria.Filters?.Any())
            {
                return;
            }

            CurrentQueryable = CurrentQueryable.Query(whereBuilder =>
            {
                Criteria.Filters.ForEach(filter => ApplyFilter <TSource>(whereBuilder, filter));
            });
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        /// <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));
        }
예제 #8
0
        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&lt;object&gt;</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));
 }
예제 #12
0
        public IQueryable <TElement> CreateQuery <TElement>(Expression expression)
        {
            var query = OriginalProvider.CreateQuery <TElement>(expression);

            return(CurrentQueryable.CreateOrderedQueryable(query as IOrderedQueryable <TElement>));
        }