Skip to main content
All docs
V26.1
  • GridCustomDataSourceTotalSummaryOptions Class

    Namespace: DevExpress.Blazor

    Assembly: DevExpress.Blazor.Grid.v26.1.dll

    NuGet Package: DevExpress.Blazor

    Declaration

    public class GridCustomDataSourceTotalSummaryOptions :
        GridCustomDataSourceOptions

    Remarks

    If standard data binding modes do not meet specific business requirements, you can implement your own data provider. To do so, create a GridCustomDataSource descendant and assign it to the Grid or TreeList component’s Data property.

    The following code snippet implements a custom data provider’s GetTotalSummaryAsync method:

    View Example: Custom Data Source Binding using Entity Framework Core

    using DevExpress.Blazor;
    using DevExpress.Data.Filtering;
    using DevExpress.Data.Filtering.Helpers;
    using CustomDataSource.Models;
    using System.Collections;
    using System.Linq.Expressions;
    using DevExpress.Data.Linq;
    using DevExpress.Data.Linq.Helpers;
    using Microsoft.EntityFrameworkCore;
    
    namespace CustomDataSource.Services;
    
    public class OrdersDataSource : GridCustomDataSource, IDisposable {
        protected override Type DataItemType => typeof(Order);
        private readonly NorthwindContext _context;
        private bool _disposed = false;
    
        public OrdersDataSource(IDbContextFactory<NorthwindContext> contextFactory) {
            _context = contextFactory.CreateDbContext();
        } 
        // ...
        public override async Task<IList> GetTotalSummaryAsync(GridCustomDataSourceTotalSummaryOptions options, CancellationToken cancellationToken) {
            var filteredQuery = ApplyFiltering(options.FilterCriteria, _context.Orders);
    
            var summaryQuery = GetGroupByAndSelectQuery(options.SummaryInfo, filteredQuery, true);
            var result = await summaryQuery.FirstOrDefaultAsync(cancellationToken);
            return result != null
                ? result
                    .Select(d => d.Value)
                    .ToList()
                : null;
        }
        // ...
        private static IQueryable<Order> ApplyFiltering(CriteriaOperator criteria, IQueryable<Order> queryableSource) {
            return !criteria.ReferenceEqualsNull()
                ? (IQueryable<Order>)queryableSource.AppendWhere(
                    new CriteriaToEFExpressionConverter(queryableSource.Provider.GetType()), criteria)
                : queryableSource;
        }
        // ...
        private static IQueryable<Dictionary<string, object>> GetGroupByAndSelectQuery(IReadOnlyList<GridCustomDataSourceSummaryInfo> summaryInfoList,
            IQueryable<Order> queryableSource, bool totalSummary, string groupedFieldName = "") {
            IQueryable groupedQuery;
            Type groupedPropertyType;
            if (totalSummary) {
                groupedPropertyType = typeof(int);
                groupedQuery = queryableSource.GroupBy(x => 1);
            } else {
                var parameter = Expression.Parameter(typeof(Order));
                var property = Expression.Property(parameter, groupedFieldName);
                groupedPropertyType = property.Type;
                var groupLambda = Expression.Lambda(property, parameter);
    
                var groupByCall = Expression.Call(typeof(Queryable), "GroupBy", new[] { typeof(Order), groupedPropertyType },
                    queryableSource.Expression, groupLambda);
                groupedQuery = queryableSource.Provider.CreateQuery(groupByCall);
            }
    
            var groupType = typeof(IGrouping<,>).MakeGenericType(groupedPropertyType, typeof(Order));
            var group = Expression.Parameter(groupType);
    
            // defining a dictionary that will hold group info
            var dictItems = new List<ElementInit>();
            var addMethod = typeof(Dictionary<string, object>).GetMethod("Add");
            if (!totalSummary) {
                dictItems.AddRange(new List<ElementInit> {
                    Expression.ElementInit(addMethod, Expression.Constant("Value"),
                        Expression.Convert(Expression.Property(group, "Key"), typeof(object))
                    ),
                    Expression.ElementInit(addMethod, Expression.Constant("DataItemCount"),
                        Expression.Convert(Expression.Call(typeof(Enumerable), "Count",
                            new[] { typeof(Order) }, group), typeof(object))
                    )
                });
            }
    
            for (int i = 0; i < summaryInfoList.Count; i++) {
                var summaryInfo = summaryInfoList[i];
    
                var groupSummaryCall = GetGroupSummaryCall(summaryInfo, group);
                dictItems.Add(Expression.ElementInit(addMethod, Expression.Constant("Summary_" + i),
                    Expression.Convert(groupSummaryCall, typeof(object))));
            }
    
            var dictInit = Expression.ListInit(Expression.New(typeof(Dictionary<string, object>)), dictItems);
    
            // creating the select query
            Type selectFuncType = typeof(Func<,>).MakeGenericType(groupType, typeof(Dictionary<string, object>));
            var selectLambda = Expression.Lambda(selectFuncType, dictInit, group);
            var selectCall = Expression.Call(typeof(Queryable), "Select",
                new[] { groupedQuery.ElementType, typeof(Dictionary<string, object>) },
                groupedQuery.Expression, selectLambda);
    
            return groupedQuery.Provider.CreateQuery<Dictionary<string, object>>(selectCall);
        }
    
        private static Expression GetGroupSummaryCall(GridCustomDataSourceSummaryInfo summaryInfo,
            Expression group) {
            var parameter = Expression.Parameter(typeof(Order));
            var property = Expression.Property(parameter, summaryInfo.FieldName);
            var summaryLambda = Expression.Lambda(property, parameter);
    
            switch (summaryInfo.SummaryType) {
                case GridSummaryItemType.Avg:
                    return Expression.Call(typeof(Enumerable), "Average", new[] { typeof(Order) },
                        group, summaryLambda);
                case GridSummaryItemType.Count:
                    return Expression.Call(typeof(Enumerable), "Count", new[] { typeof(Order) },
                        group);
                case GridSummaryItemType.Max:
                    return Expression.Call(typeof(Enumerable), "Max", new[] { typeof(Order), property.Type },
                        group, summaryLambda);
                case GridSummaryItemType.Min:
                    return Expression.Call(typeof(Enumerable), "Min", new[] { typeof(Order), property.Type },
                        group, summaryLambda);
                case GridSummaryItemType.Sum:
                    return Expression.Call(typeof(Enumerable), "Sum", new[] { typeof(Order) },
                        group, summaryLambda);
                default:
                    throw new NotSupportedException(summaryInfo.SummaryType.ToString());
            }
        }
        // ...
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing) {
            if (!_disposed) {
                if (disposing) {
                    _context?.Dispose();
                }
                _disposed = true;
            }
        }
        // ...
    }
    

    Inheritance

    Object
    GridCustomDataSourceOptions
    GridCustomDataSourceTotalSummaryOptions
    See Also