Hi!
There is any way to create custom aggregate for QueryableDataProvider?
I want to create CustomDistinct aggregate, I did it successfully for LocalDataSourceProvider, and I need it also for QueryableDataProvider.
Here is my code, unfortunately, it is not working at all..
Hi!
There is any way to create custom aggregate for QueryableDataProvider?
I want to create CustomDistinct aggregate, I did it successfully for LocalDataSourceProvider, and I neet also for QueryableDataProvider.
Here is my code, unfurtonately, it is not working at all..
I see "CountDistinct" in "More aggregate options" window, but when i choose it, the pivot got an error.
using System;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;using Telerik.Pivot.Core;using Telerik.Pivot.Core.Fields;using Telerik.Pivot.Queryable;namespace YA.Pivot.Queryable{ public class MyQueryableDataProvider : QueryableDataProvider { protected override void OnPrepareDescriptionForField(PrepareDescriptionForFieldEventArgs args) { base.OnPrepareDescriptionForField(args); if (args.DescriptionType == DataProviderDescriptionType.Aggregate) { var old = args.Description as QueryablePropertyAggregateDescriptionBase; args.Description = new CustomPropertyAggregateDescription() { PropertyName = old.PropertyName, FunctionName = old.FunctionName, AggregateFunction = old.AggregateFunction, CustomName = old.CustomName, StringFormat = old.StringFormat }; } } } internal class CustomPropertyAggregateDescription : QueryablePropertyAggregateDescriptionBase { private enum MyAggregateFunctions { CountDistinct = -100 } protected override Cloneable CreateInstanceCore() { return new CustomPropertyAggregateDescription() { AggregateFunction = this.AggregateFunction, CustomName = this.CustomName, FunctionName = this.FunctionName, PropertyName = this.PropertyName, StringFormat = this.StringFormat, StringFormatSelector = this.StringFormatSelector, TotalFormat = this.TotalFormat }; } private bool IsCountDistinct => (int)base.AggregateFunction == (int)MyAggregateFunctions.CountDistinct; protected override Expression CreateAggregateExpression(Expression enumerableExpression, string aggregatedValueName) { if (enumerableExpression == null) { throw new ArgumentNullException(nameof(enumerableExpression)); } if (IsCountDistinct) { return CreateCountDistinctExpression(enumerableExpression, aggregatedValueName); } return base.CreateAggregateExpression(enumerableExpression, aggregatedValueName); } private Expression CreateCountDistinctExpression(Expression enumerableExpression, string aggregatedValueName) { Type itemType = TypeExtensions.ExtractItemTypeFromEnumerableType(enumerableExpression.Type); var selectParamExp = Expression.Parameter(itemType, "e"); var selectPropAccessExp = Expression.Property(selectParamExp, aggregatedValueName); LambdaExpression selectLambdaExpression = Expression.Lambda(selectPropAccessExp, selectParamExp); var select = Expression.Call( typeof(Enumerable), "Select", new[] { itemType, selectLambdaExpression.Body.Type }, enumerableExpression, selectLambdaExpression); var distinct = Expression.Call( typeof(Enumerable), "Distinct", new[] { selectLambdaExpression.Body.Type }, select); var count = Expression.Call( typeof(Enumerable), "Count", new[] { selectLambdaExpression.Body.Type }, distinct); return count; } protected override IEnumerable<object> SupportedAggregateFunctions => base.SupportedAggregateFunctions.Concat(new object[] { MyAggregateFunctions.CountDistinct }); } internal static class TypeExtensions { public static Type ExtractItemTypeFromEnumerableType(Type type) { var enumerableType = type.FindGenericType(typeof(IEnumerable<>)); if (enumerableType == null) { throw new ArgumentException("Provided type is not IEnumerable<>", nameof(type)); } return enumerableType.GetGenericArguments().First(); } private static Type FindGenericType(this Type type, Type genericType) { while (type != null && type != typeof(object)) { if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType) { return type; } if (genericType.IsInterface) { foreach (Type intfType in type.GetInterfaces()) { Type found = intfType.FindGenericType(genericType); if (found != null) { return found; } } } type = type.BaseType; } return null; } }}