Hi all,
I've implemented Virtual Scrolling with Custom Binding Directive.
Unfortunately, I have an issue when converting State to query string using toDataSourceRequestString:
if virtual scrolling requests to skip 49 records, with pageSize =100 it gets converted by toDataSourceRequestString to Page=1&pageSize=100
and incorrect results are returned.
Please suggest fix or workaround.
Thanks,
Yuriy
5 Answers, 1 is accepted
Indeed, this is the expected behavior. If skip is 49 and pageSize is 100, passing the state to the toDataSourceRequestString method will return "page=1&pageSize=100".
This is valid because when we skip 49 rows we are still on page one and virtual scrolling requires to always load a batch equal to the [pageSize] property.
Please check the following sample plunker and inspect the browser console for clarification (scroll until you pass row 100 in order to trigger the dataStateChange event):
http://plnkr.co/edit/VopERvycY4vQHwIodDxd?p=preview
Regards,
Svetlin
Progress Telerik
Hi Svetlin,
thank you for the answer.
I did examined your example and found this part:
private loadProducts(): void {
this.gridView = {
data: this.data.slice(this.skip, this.skip + this.pageSize),
total: this.data.length
};
}
This is correct, you fetched a right portion of data, because you have a SKIP and TAKE.
In my case if, for example, when bind method is called of my custom DataBindingDirective, state={skip:49, take=100}. So, I pass this to toDataSourceRequestString(state) and then request goes to my WebAPI service. It receives only "?page=1&pageSize=100" and thus not able to skip first part of data, since SKIP=49 is lost.
Thanks,
Yuriy
The Kendo UI for Angular implementation is slightly different than the one for Kendo UI for JQuery.
When integrating Kendo UI for Angular with ASP.NET Core we can pass the skip number to the server only as a separate parameter. (This is due to the fact that DataSourceRequest type does not have a Skip property)
This infers that the developer needs to implement custom server side methods for grouping, sorting, filtering, and paging. An example of how these can be implemented can be seen at the following link in the CustomAjaxBindingController.cs tab:
https://demos.telerik.com/aspnet-mvc/grid/customajaxbinding
I hope this helps. Please let me know in case you need further assistance for this case.
Regards,
Svetlin
Progress Telerik
Hi <user>,
you wrote "we can pass the skip number to the server only as a separate parameter. ".
Great, but can I mix my custom SKIP parameter and ToDataSourceResult? It would be nice not to rewrite all IQueryable extensions for filters, sorting, etc.
Thanks,
Yuriy
Unfortunately, the toDataSourceResult method accepts only an argument of type DataSourceRequest:
public class DataSourceRequest{ public DataSourceRequest(); public int Page { get; set; } public int PageSize { get; set; } public IList<SortDescriptor> Sorts { get; set; } public IList<IFilterDescriptor> Filters { get; set; } public IList<GroupDescriptor> Groups { get; set; } public IList<AggregateDescriptor> Aggregates { get; set; }}So, in the built in functionality, a custom skip parameter cannot be mixed with the ToDataSourceResult method.
For further reference (if you want to use the skip as a part of the ToDataSourceResult method a customization of the source code will be required) I am sending the source code for the ToDataSourceResult() method as an IQueryable extension:
private static DataSourceResult CreateDataSourceResult<TModel, TResult>(this IQueryable queryable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { var result = new DataSourceResult(); var data = queryable; var filters = new List<IFilterDescriptor>(); if (request.Filters != null) { filters.AddRange(request.Filters); } if (filters.Any()) { data = data.Where(filters); } var sort = new List<SortDescriptor>(); if (request.Sorts != null) { sort.AddRange(request.Sorts); } var temporarySortDescriptors = new List<SortDescriptor>(); IList<GroupDescriptor> groups = new List<GroupDescriptor>(); if (request.Groups != null) { groups.AddRange(request.Groups); } var aggregates = new List<AggregateDescriptor>(); if (request.Aggregates != null) { aggregates.AddRange(request.Aggregates); } if (aggregates.Any()) { var dataSource = data.AsQueryable(); var source = dataSource; if (filters.Any()) { source = dataSource.Where(filters); } result.AggregateResults = source.Aggregate(aggregates.SelectMany(a => a.Aggregates)); if (groups.Any() && aggregates.Any()) { groups.Each(g => g.AggregateFunctions.AddRange(aggregates.SelectMany(a => a.Aggregates))); } } result.Total = data.Count(); if (!sort.Any() && queryable.Provider.IsEntityFrameworkProvider()) { // The Entity Framework provider demands OrderBy before calling Skip. SortDescriptor sortDescriptor = new SortDescriptor { Member = queryable.ElementType.FirstSortableProperty() }; sort.Add(sortDescriptor); temporarySortDescriptors.Add(sortDescriptor); } if (groups.Any()) { groups.Reverse().Each(groupDescriptor => { var sortDescriptor = new SortDescriptor { Member = groupDescriptor.Member, SortDirection = groupDescriptor.SortDirection }; sort.Insert(0, sortDescriptor); temporarySortDescriptors.Add(sortDescriptor); }); } if (sort.Any()) { data = data.Sort(sort); } var notPagedData = data; data = data.Page(request.Page - 1, request.PageSize); if (groups.Any()) { data = data.GroupBy(notPagedData, groups); } result.Data = data.Execute(selector); if (modelState != null && !modelState.IsValid) { result.Errors = modelState.SerializeErrors(); } temporarySortDescriptors.Each(sortDescriptor => sort.Remove(sortDescriptor)); return result; }All other methods are eventually calling the one above with the respective arguments. Here is the whole code of the QueryableExtensions.cs file:
namespace Kendo.Mvc.Extensions{ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using System.Web.Mvc; using Kendo.Mvc; using Kendo.Mvc.Infrastructure; using Kendo.Mvc.Infrastructure.Implementation; using Infrastructure.Implementation.Expressions; using Kendo.Mvc.UI; /// <summary> /// Provides extension methods to process DataSourceRequest. /// </summary> public static class QueryableExtensions { private static DataSourceResult ToDataSourceResult(this DataTableWrapper enumerable, DataSourceRequest request) { var filters = new List<IFilterDescriptor>(); if (request.Filters != null) { filters.AddRange(request.Filters); } if (filters.Any()) { var dataTable = enumerable.Table; filters.SelectMemberDescriptors() .Each(f => f.MemberType = GetFieldByTypeFromDataColumn(dataTable, f.Member)); } var group = new List<GroupDescriptor>(); if (request.Groups != null) { group.AddRange(request.Groups); } if (group.Any()) { var dataTable = enumerable.Table; group.Each(g => g.MemberType = GetFieldByTypeFromDataColumn(dataTable, g.Member)); } var result = enumerable.AsEnumerable().ToDataSourceResult(request); result.Data = result.Data.SerializeToDictionary(enumerable.Table); return result; } private static Type GetFieldByTypeFromDataColumn(DataTable dataTable, string memberName) { return dataTable.Columns.Contains(memberName) ? dataTable.Columns[memberName].DataType : null; } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty resullt. /// </summary> /// <param name="dataTable">An instance of <see cref="DataTable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A <see cref="DataSourceResult" /> object, which contains the processed data after /// paging, sorting, filtering and grouping are applied. /// </returns> public static DataSourceResult ToDataSourceResult(this DataTable dataTable, DataSourceRequest request) { return dataTable.WrapAsEnumerable().ToDataSourceResult(request); } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty resullt. /// </summary> /// <param name="dataTable">An instance of <see cref="DataTable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A Task of <see cref="DataSourceResult" /> object, which contains the processed data after /// paging, sorting, filtering and grouping are applied. /// It can be called with the "await" keyword for asynchronous operation. /// </returns> public static Task<DataSourceResult> ToDataSourceResultAsync(this DataTable dataTable, DataSourceRequest request) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(dataTable, request)); } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="enumerable">An instance of <see cref="IEnumerable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A <see cref="DataSourceResult" /> object, which contains the processed data after /// paging, sorting, filtering and grouping are applied. /// </returns> public static DataSourceResult ToDataSourceResult(this IEnumerable enumerable, DataSourceRequest request) { return enumerable.AsQueryable().ToDataSourceResult(request); } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="enumerable">An instance of <see cref="IEnumerable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A Task of <see cref="DataSourceResult" /> object, which contains the processed data /// after paging, sorting, filtering and grouping are applied. /// It can be called with the "await" keyword for asynchronous operation. /// </returns> public static Task<DataSourceResult> ToDataSourceResultAsync(this IEnumerable enumerable, DataSourceRequest request) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(enumerable, request)); } public static DataSourceResult ToDataSourceResult(this IEnumerable enumerable, DataSourceRequest request, ModelStateDictionary modelState) { return enumerable.AsQueryable().ToDataSourceResult(request, modelState); } public static Task<DataSourceResult> ToDataSourceResultAsync( this IEnumerable enumerable, DataSourceRequest request, ModelStateDictionary modelState) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(enumerable, request, modelState)); } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="queryable">An instance of <see cref="IQueryable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A <see cref="DataSourceResult" /> object, which contains the processed data after paging, sorting, filtering and grouping are applied. /// </returns> public static DataSourceResult ToDataSourceResult(this IQueryable queryable, DataSourceRequest request) { return queryable.ToDataSourceResult(request, null); } /// <summary> /// Applies paging, sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="queryable">An instance of <see cref="IQueryable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A Task of <see cref="DataSourceResult" /> object, which contains the processed data /// after paging, sorting, filtering and grouping are applied. /// It can be called with the "await" keyword for asynchronous operation. /// </returns> public static Task<DataSourceResult> ToDataSourceResultAsync(this IQueryable queryable, DataSourceRequest request) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(queryable, request)); } public static DataSourceResult ToDataSourceResult<TModel, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return enumerable.AsQueryable().CreateDataSourceResult(request, null, selector); } public static Task<DataSourceResult> ToDataSourceResultAsync<TModel, TResult>( this IEnumerable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(enumerable, request, selector)); } public static DataSourceResult ToDataSourceResult<TModel, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return enumerable.AsQueryable().CreateDataSourceResult(request, modelState, selector); } public static Task<DataSourceResult> ToDataSourceResultAsync<TModel, TResult>( this IEnumerable<TModel> enumerable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(enumerable, request, modelState, selector)); } public static DataSourceResult ToDataSourceResult<TModel, TResult>(this IQueryable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return enumerable.CreateDataSourceResult(request, null, selector); } public static Task<DataSourceResult> ToDataSourceResultAsync<TModel, TResult> (this IQueryable<TModel> queryable, DataSourceRequest request, Func<TModel, TResult> selector) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(queryable, request, selector)); } public static DataSourceResult ToDataSourceResult<TModel, TResult>(this IQueryable<TModel> enumerable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return enumerable.CreateDataSourceResult(request, modelState, selector); } public static Task<DataSourceResult> ToDataSourceResultAsync<TModel, TResult>( this IQueryable<TModel> queryable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(queryable, request, modelState, selector)); ; } public static DataSourceResult ToDataSourceResult(this IQueryable queryable, DataSourceRequest request, ModelStateDictionary modelState) { return queryable.CreateDataSourceResult<object, object>(request, modelState, null); } public static Task<DataSourceResult> ToDataSourceResultAsync(this IQueryable queryable, DataSourceRequest request, ModelStateDictionary modelState) { return CreateDataSourceResultAsync(() => QueryableExtensions.ToDataSourceResult(queryable, request, modelState)); } private static DataSourceResult CreateDataSourceResult<TModel, TResult>(this IQueryable queryable, DataSourceRequest request, ModelStateDictionary modelState, Func<TModel, TResult> selector) { var result = new DataSourceResult(); var data = queryable; var filters = new List<IFilterDescriptor>(); if (request.Filters != null) { filters.AddRange(request.Filters); } if (filters.Any()) { data = data.Where(filters); } var sort = new List<SortDescriptor>(); if (request.Sorts != null) { sort.AddRange(request.Sorts); } var temporarySortDescriptors = new List<SortDescriptor>(); IList<GroupDescriptor> groups = new List<GroupDescriptor>(); if (request.Groups != null) { groups.AddRange(request.Groups); } var aggregates = new List<AggregateDescriptor>(); if (request.Aggregates != null) { aggregates.AddRange(request.Aggregates); } if (aggregates.Any()) { var dataSource = data.AsQueryable(); var source = dataSource; if (filters.Any()) { source = dataSource.Where(filters); } result.AggregateResults = source.Aggregate(aggregates.SelectMany(a => a.Aggregates)); if (groups.Any() && aggregates.Any()) { groups.Each(g => g.AggregateFunctions.AddRange(aggregates.SelectMany(a => a.Aggregates))); } } result.Total = data.Count(); if (!sort.Any() && queryable.Provider.IsEntityFrameworkProvider()) { // The Entity Framework provider demands OrderBy before calling Skip. SortDescriptor sortDescriptor = new SortDescriptor { Member = queryable.ElementType.FirstSortableProperty() }; sort.Add(sortDescriptor); temporarySortDescriptors.Add(sortDescriptor); } if (groups.Any()) { groups.Reverse().Each(groupDescriptor => { var sortDescriptor = new SortDescriptor { Member = groupDescriptor.Member, SortDirection = groupDescriptor.SortDirection }; sort.Insert(0, sortDescriptor); temporarySortDescriptors.Add(sortDescriptor); }); } if (sort.Any()) { data = data.Sort(sort); } var notPagedData = data; data = data.Page(request.Page - 1, request.PageSize); if (groups.Any()) { data = data.GroupBy(notPagedData, groups); } result.Data = data.Execute(selector); if (modelState != null && !modelState.IsValid) { result.Errors = modelState.SerializeErrors(); } temporarySortDescriptors.Each(sortDescriptor => sort.Remove(sortDescriptor)); return result; } private static Task<DataSourceResult> CreateDataSourceResultAsync(Func<DataSourceResult> expression) { // Task.Run() is not available in .NET 4.0 return Task.Factory.StartNew(expression, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } private static IQueryable CallQueryableMethod(this IQueryable source, string methodName, LambdaExpression selector) { IQueryable query = source.Provider.CreateQuery( Expression.Call( typeof(Queryable), methodName, new[] { source.ElementType, selector.Body.Type }, source.Expression, Expression.Quote(selector))); return query; } /// <summary> /// Sorts the elements of a sequence using the specified sort descriptors. /// </summary> /// <param name="source">A sequence of values to sort.</param> /// <param name="sortDescriptors">The sort descriptors used for sorting.</param> /// <returns> /// An <see cref="IQueryable" /> whose elements are sorted according to a <paramref name="sortDescriptors"/>. /// </returns> public static IQueryable Sort(this IQueryable source, IEnumerable<SortDescriptor> sortDescriptors) { var builder = new SortDescriptorCollectionExpressionBuilder(source, sortDescriptors); return builder.Sort(); } /// <summary> /// Pages through the elements of a sequence until the specified /// <paramref name="pageIndex"/> using <paramref name="pageSize"/>. /// </summary> /// <param name="source">A sequence of values to page.</param> /// <param name="pageIndex">Index of the page.</param> /// <param name="pageSize">Size of the page.</param> /// <returns> /// An <see cref="IQueryable" /> whose elements are at the specified <paramref name="pageIndex"/>. /// </returns> public static IQueryable Page(this IQueryable source, int pageIndex, int pageSize) { IQueryable query = source; query = query.Skip(pageIndex * pageSize); if (pageSize > 0) { query = query.Take(pageSize); } return query; } /// <summary> /// Projects each element of a sequence into a new form. /// </summary> /// <returns> /// An <see cref="IQueryable" /> whose elements are the result of invoking a /// projection selector on each element of <paramref name="source" />. /// </returns> /// <param name="source"> A sequence of values to project. </param> /// <param name="selector"> A projection function to apply to each element. </param> public static IQueryable Select(this IQueryable source, LambdaExpression selector) { return source.CallQueryableMethod("Select", selector); } /// <summary> /// Groups the elements of a sequence according to a specified key selector function. /// </summary> /// <param name="source"> An <see cref="IQueryable" /> whose elements to group.</param> /// <param name="keySelector"> A function to extract the key for each element.</param> /// <returns> /// An <see cref="IQueryable"/> with <see cref="IGrouping{TKey,TElement}"/> items, /// whose elements contains a sequence of objects and a key. /// </returns> public static IQueryable GroupBy(this IQueryable source, LambdaExpression keySelector) { return source.CallQueryableMethod("GroupBy", keySelector); } /// <summary> /// Sorts the elements of a sequence in ascending order according to a key. /// </summary> /// <returns> /// An <see cref="IQueryable" /> whose elements are sorted according to a key. /// </returns> /// <param name="source"> /// A sequence of values to order. /// </param> /// <param name="keySelector"> /// A function to extract a key from an element. /// </param> public static IQueryable OrderBy(this IQueryable source, LambdaExpression keySelector) { return source.CallQueryableMethod("OrderBy", keySelector); } /// <summary> /// Sorts the elements of a sequence in descending order according to a key. /// </summary> /// <returns> /// An <see cref="IQueryable" /> whose elements are sorted in descending order according to a key. /// </returns> /// <param name="source"> /// A sequence of values to order. /// </param> /// <param name="keySelector"> /// A function to extract a key from an element. /// </param> public static IQueryable OrderByDescending(this IQueryable source, LambdaExpression keySelector) { return source.CallQueryableMethod("OrderByDescending", keySelector); } /// <summary> /// Calls <see cref="OrderBy(System.Linq.IQueryable,System.Linq.Expressions.LambdaExpression)"/> /// or <see cref="OrderByDescending"/> depending on the <paramref name="sortDirection"/>. /// </summary> /// <param name="source">The source.</param> /// <param name="keySelector">The key selector.</param> /// <param name="sortDirection">The sort direction.</param> /// <returns> /// An <see cref="IQueryable" /> whose elements are sorted according to a key. /// </returns> public static IQueryable OrderBy(this IQueryable source, LambdaExpression keySelector, ListSortDirection? sortDirection) { if (sortDirection.HasValue) { if (sortDirection.Value == ListSortDirection.Ascending) { return source.OrderBy(keySelector); } return source.OrderByDescending(keySelector); } return source; } /// <summary> /// Groups the elements of a sequence according to a specified <paramref name="groupDescriptors"/>. /// </summary> /// <param name="source"> An <see cref="IQueryable" /> whose elements to group. </param> /// <param name="groupDescriptors">The group descriptors used for grouping.</param> /// <returns> /// An <see cref="IQueryable"/> with <see cref="IGroup"/> items, /// whose elements contains a sequence of objects and a key. /// </returns> public static IQueryable GroupBy(this IQueryable source, IEnumerable<GroupDescriptor> groupDescriptors) { return source.GroupBy(source, groupDescriptors); } public static IQueryable GroupBy(this IQueryable source, IQueryable notPagedData, IEnumerable<GroupDescriptor> groupDescriptors) { var builder = new GroupDescriptorCollectionExpressionBuilder(source, groupDescriptors, notPagedData); builder.Options.LiftMemberAccessToNull = source.Provider.IsLinqToObjectsProvider(); return builder.CreateQuery(); } /// <summary> /// Calculates the results of given aggregates functions on a sequence of elements. /// </summary> /// <param name="source"> An <see cref="IQueryable" /> whose elements will /// be used for aggregate calculation.</param> /// <param name="aggregateFunctions">The aggregate functions.</param> /// <returns>Collection of <see cref="AggregateResult"/>s calculated for each function.</returns> public static AggregateResultCollection Aggregate(this IQueryable source, IEnumerable<AggregateFunction> aggregateFunctions) { var functions = aggregateFunctions.ToList(); if (functions.Count > 0) { var builder = new QueryableAggregatesExpressionBuilder(source, functions); builder.Options.LiftMemberAccessToNull = source.Provider.IsLinqToObjectsProvider(); var groups = builder.CreateQuery(); foreach (AggregateFunctionsGroup group in groups) { return group.GetAggregateResults(functions); } } return new AggregateResultCollection(); } /// <summary> /// Filters a sequence of values based on a predicate. /// </summary> /// <returns> /// An <see cref="IQueryable" /> that contains elements from the input sequence /// that satisfy the condition specified by <paramref name="predicate" />. /// </returns> /// <param name="source"> An <see cref="IQueryable" /> to filter.</param> /// <param name="predicate"> A function to test each element for a condition.</param> public static IQueryable Where(this IQueryable source, Expression predicate) { return source.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Where", new[] { source.ElementType }, source.Expression, Expression.Quote(predicate))); } /// <summary> /// Filters a sequence of values based on a collection of <see cref="IFilterDescriptor"/>. /// </summary> /// <param name="source">The source.</param> /// <param name="filterDescriptors">The filter descriptors.</param> /// <returns> /// An <see cref="IQueryable" /> that contains elements from the input sequence /// that satisfy the conditions specified by each filter descriptor in <paramref name="filterDescriptors" />. /// </returns> public static IQueryable Where(this IQueryable source, IEnumerable<IFilterDescriptor> filterDescriptors) { if (filterDescriptors.Any()) { var parameterExpression = Expression.Parameter(source.ElementType, "item"); var expressionBuilder = new FilterDescriptorCollectionExpressionBuilder(parameterExpression, filterDescriptors); expressionBuilder.Options.LiftMemberAccessToNull = source.Provider.IsLinqToObjectsProvider(); var predicate = expressionBuilder.CreateFilterExpression(); return source.Where(predicate); } return source; } /// <summary> /// Returns a specified number of contiguous elements from the start of a sequence. /// </summary> /// <returns> /// An <see cref="IQueryable" /> that contains the specified number /// of elements from the start of <paramref name="source" />. /// </returns> /// <param name="source"> The sequence to return elements from.</param> /// <param name="count"> The number of elements to return. </param> /// <exception cref="ArgumentNullException"><paramref name="source" /> is null. </exception> public static IQueryable Take(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Take", new Type[] { source.ElementType }, source.Expression, Expression.Constant(count))); } /// <summary> /// Bypasses a specified number of elements in a sequence /// and then returns the remaining elements. /// </summary> /// <returns> /// An <see cref="IQueryable" /> that contains elements that occur /// after the specified index in the input sequence. /// </returns> /// <param name="source"> /// An <see cref="IQueryable" /> to return elements from. /// </param> /// <param name="count"> /// The number of elements to skip before returning the remaining elements. /// </param> /// <exception cref="ArgumentNullException"> <paramref name="source" /> is null.</exception> public static IQueryable Skip(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Skip", new Type[] { source.ElementType }, source.Expression, Expression.Constant(count))); } /// <summary> Returns the number of elements in a sequence.</summary> /// <returns> The number of elements in the input sequence.</returns> /// <param name="source"> /// The <see cref="IQueryable" /> that contains the elements to be counted. /// </param> /// <exception cref="ArgumentNullException"> <paramref name="source" /> is null.</exception> public static int Count(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.Execute<int>( Expression.Call( typeof(Queryable), "Count", new Type[] { source.ElementType }, source.Expression)); } /// <summary> Returns the element at a specified index in a sequence.</summary> /// <returns> The element at the specified position in <paramref name="source" />.</returns> /// <param name="source"> An <see cref="IQueryable" /> to return an element from.</param> /// <param name="index"> The zero-based index of the element to retrieve.</param> /// <exception cref="ArgumentNullException"> <paramref name="source" /> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"> <paramref name="index" /> is less than zero.</exception> public static object ElementAt(this IQueryable source, int index) { if (source == null) throw new ArgumentNullException("source"); if (index < 0) throw new ArgumentOutOfRangeException("index"); return source.Provider.Execute( Expression.Call( typeof(Queryable), "ElementAt", new Type[] { source.ElementType }, source.Expression, Expression.Constant(index))); } /// <summary> /// Produces the set union of two sequences by using the default equality comparer. /// </summary> /// <returns> /// An <see cref="IQueryable" /> that contains the elements from both input sequences, excluding duplicates. /// </returns> /// <param name="source"> /// An <see cref="IQueryable" /> whose distinct elements form the first set for the union. /// </param> /// <param name="second"> /// An <see cref="IQueryable" /> whose distinct elements form the first set for the union. /// </param> /// <exception cref="ArgumentNullException"> <paramref name="source" /> is null.</exception> public static IQueryable Union(this IQueryable source, IQueryable second) { IQueryable query = source.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Union", new[] { source.ElementType }, source.Expression, second.Expression)); return query; } private static IEnumerable Execute<TModel, TResult>(this IQueryable source, Func<TModel, TResult> selector) { if (source == null) throw new ArgumentNullException("source"); if (source is DataTableWrapper) { return source; } var type = source.ElementType; if (selector != null) { var groups = new List<AggregateFunctionsGroup>(); if (type == typeof(AggregateFunctionsGroup)) { foreach (AggregateFunctionsGroup group in source) { group.Items = group.Items.AsQueryable().Execute(selector); groups.Add(group); } return groups; } else { var list = new List<TResult>(); foreach (TModel item in source) { list.Add(selector(item)); } return list; } } else { var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type)); foreach (var item in source) { list.Add(item); } return list; } } /// <summary> /// Applies sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="enumerable">An instance of <see cref="IEnumerable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A <see cref="TreeDataSourceResult" /> object, which contains the processed data after sorting, filtering and grouping are applied. /// </returns> public static TreeDataSourceResult ToTreeDataSourceResult(this IEnumerable enumerable, DataSourceRequest request) { return enumerable.AsQueryable().ToTreeDataSourceResult(request, null); } /// <summary> /// Applies sorting, filtering and grouping using the information from the DataSourceRequest object. /// If the collection is already paged, the method returns an empty result. /// </summary> /// <param name="enumerable">An instance of <see cref="IEnumerable" />.</param> /// <param name="request">An instance of <see cref="DataSourceRequest" />.</param> /// <returns> /// A Task of <see cref="TreeDataSourceResult" /> object, which contains the processed data /// after sorting, filtering and grouping are applied. /// It can be called with the "await" keyword for asynchronous operation. /// </returns> public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync(this IEnumerable enumerable, DataSourceRequest request) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request)); } public static TreeDataSourceResult ToTreeDataSourceResult(this IEnumerable enumerable, DataSourceRequest request, ModelStateDictionary modelState) { return enumerable.AsQueryable().CreateTreeDataSourceResult<object, object, object, object>(request, null, null, modelState, null, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync(this IEnumerable enumerable, DataSourceRequest request, ModelStateDictionary modelState) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, modelState)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, TResult>(this IQueryable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return enumerable.ToTreeDataSourceResult<TModel, object, object, TResult>(request, null, null, selector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, TResult>( this IQueryable<TModel> queryable, DataSourceRequest request, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return enumerable.ToTreeDataSourceResult<TModel, object, object, TResult>(request, null, null, selector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IQueryable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector) { return enumerable.CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, null, null, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IQueryable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector) { return enumerable.CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, null, null, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, rootSelector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, Func<TModel, TResult> selector) { return queryable.CreateTreeDataSourceResult(request, idSelector, parentIDSelector, null, selector, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, rootSelector, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState) { return queryable.ToTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, modelState, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, modelState)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IQueryable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState) { return enumerable.CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, modelState, null, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, rootSelector, modelState)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Func<TModel, TResult> selector) { return queryable.CreateTreeDataSourceResult(request, idSelector, parentIDSelector, null, selector, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return queryable.CreateTreeDataSourceResult(request, idSelector, parentIDSelector, modelState, selector, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, modelState, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return queryable.CreateTreeDataSourceResult(request, idSelector, parentIDSelector, modelState, selector, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IQueryable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(queryable, request, idSelector, parentIDSelector, rootSelector, modelState, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector) { return enumerable.AsQueryable().CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, null, null, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector) { return enumerable.AsQueryable().CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, null, null, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, rootSelector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IEnumerable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, Func<TModel, TResult> selector) { return queryable.AsQueryable().CreateTreeDataSourceResult(request, idSelector, parentIDSelector, null, selector, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, rootSelector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IEnumerable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState) { return queryable.AsQueryable().ToTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, modelState, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, modelState)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState) { return enumerable.AsQueryable().CreateTreeDataSourceResult<TModel, T1, T2, TModel>(request, idSelector, parentIDSelector, modelState, null, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, rootSelector, modelState)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IEnumerable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Func<TModel, TResult> selector) { return queryable.AsQueryable().CreateTreeDataSourceResult(request, idSelector, parentIDSelector, null, selector, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IEnumerable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return queryable.AsQueryable().CreateTreeDataSourceResult(request, idSelector, parentIDSelector, modelState, selector, null); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, modelState, selector)); } public static TreeDataSourceResult ToTreeDataSourceResult<TModel, T1, T2, TResult>(this IEnumerable<TModel> queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return queryable.AsQueryable().CreateTreeDataSourceResult(request, idSelector, parentIDSelector, modelState, selector, rootSelector); } public static Task<TreeDataSourceResult> ToTreeDataSourceResultAsync<TModel, T1, T2, TResult>(this IEnumerable<TModel> enumerable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, Expression<Func<TModel, bool>> rootSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector) { return CreateTreeDataSourceResultAsync(() => QueryableExtensions.ToTreeDataSourceResult(enumerable, request, idSelector, parentIDSelector, rootSelector, modelState, selector)); } private static Task<TreeDataSourceResult> CreateTreeDataSourceResultAsync(Func<TreeDataSourceResult> expression) { // Task.Run() is not available in .NET 4.0 return Task.Factory.StartNew(expression, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } private static TreeDataSourceResult CreateTreeDataSourceResult<TModel, T1, T2, TResult>(this IQueryable queryable, DataSourceRequest request, Expression<Func<TModel, T1>> idSelector, Expression<Func<TModel, T2>> parentIDSelector, ModelStateDictionary modelState, Func<TModel, TResult> selector, Expression<Func<TModel, bool>> rootSelector) { var result = new TreeDataSourceResult(); var data = queryable; var filters = new List<IFilterDescriptor>(); if (request.Filters != null) { filters.AddRange(request.Filters); } if (filters.Any()) { data = data.Where(filters); data = data.ParentsRecursive<TModel>(queryable, idSelector, parentIDSelector); } var filteredData = data; if (rootSelector != null) { data = data.Where(rootSelector); } var sort = new List<SortDescriptor>(); if (request.Sorts != null) { sort.AddRange(request.Sorts); } var aggregates = new List<AggregateDescriptor>(); if (request.Aggregates != null) { aggregates.AddRange(request.Aggregates); } if (aggregates.Any()) { var dataSource = data; var groups = dataSource.GroupBy(parentIDSelector); foreach (IGrouping<T2, TModel> group in groups) { result.AggregateResults.Add(Convert.ToString(group.Key), group.AggregateForLevel(filteredData, aggregates, idSelector, parentIDSelector)); } } if (sort.Any()) { data = data.Sort(sort); } result.Data = data.Execute(selector); if (modelState != null && !modelState.IsValid) { result.Errors = modelState.SerializeErrors(); } return result; } }}Please let me know in case I can provide further assistance for this case.
Regards,
Svetlin
Progress Telerik
