Home / Community & Support / Knowledge Base / Telerik Reporting / Designing Reports / Implementing custom aggregate functions.

Implementing custom aggregate functions.

Article Info

Rating: 5

Article information

Article relates to

 Telerik Reporting

Created by

 Rossen Hristov

Last modified

12 April 2011

Last modified by

 Peter


HOW-TO
Implement and use custom aggregate functions in Telerik Reporting.

SOLUTION
Along with the standard aggregate functions provided by Telerik Reporting, developers can define their own custom aggregate when needed. For the sake of this article let us assume that we need to create and use the Count Distinct aggregate function. To achieve that the developer needs to do a couple of things:

User Defined Aggregate Class

In order to separate the aggregate function logic from the report definition and to achieve better re-usability the developer needs to implement an aggregate class. User aggregates are public or internal (Public or Friend in VB.NET) classes that implement the IAggregateFunction interface.

This basic class needs to implement the following functionality:
  • Init: Called every time the accumulation of values must start over for a new subset of records from the data source.
  • Accumulate: Accumulates new argument values to the current aggregate function.
  • Merge: Merges the specified aggregate function to the current one.
  • GetValue: Returns the currently accumulated value of the aggregate function.
To better explain the pattern described above, let us take a look at the implementation of a class that counts distinct values:

[C#]
[AggregateFunction(Name = "CountDistinct",
Description = "Defines an aggregate function to count distinct values.")]

public class CountDistinctAggregate :
Telerik.Reporting.Expressions.IAggregateFunction
{
 
 
    private System.Collections.Generic.List<object> distinctValues;
    /// <summary>
    /// Initializes the current aggregate function to its initial
    /// state ready to accumulate and merge values.
    /// </summary>
    /// <remarks>
    /// This method is called every time the accumulation of values 
    /// must start over for a new subset of records from the data source.
    /// </remarks>
    public void Init()
    {
        this.distinctValues = new System.Collections.Generic.List<object>();
    }
 
    /// <summary>
    /// Accumulates new argument values to the current aggregate function.
    /// </summary>
    /// <remarks>
    /// This aggregate function accepts one argument:
    /// number - a numeric value to accumulate to the aggregate function;
    /// </remarks>
 
    public void Accumulate(object[] values)
    {
        if (!distinctValues.Contains(values[0]))
        {
            distinctValues.Add(values[0]);
        }
    }
 
 
    /// <summary>
    /// Merges the specified aggregate function to the current one.
    /// </summary>
    /// <param name="Aggregate">
    /// Specifies an aggregate function to be merged to the current one.
    /// </param>
    /// <remarks>
    /// This method allows the reporting engine to merge two accumulated
    /// subsets of the same aggregate function into a single result.
    /// </remarks>
    public void Merge(IAggregateFunction aggregate)
    {
        // Accumulate the values of the specified aggregate function.
        System.Collections.Generic.List<object> sums1 = ((CountDistinctAggregate)aggregate).distinctValues;
        foreach(object o in sums1)
        {
            this.Accumulate(new object[] { o });
        }
    }
 
    /// <summary>
    /// Returns the currently accumulated value of the aggregate function.
    /// </summary>
    /// <returns>
    /// The currently accumulated numeric value of the aggregate function.
    /// </returns>
    public object GetValue()
    {
        return this.distinctValues.Count;
    }
}

[VB.NET]
<Expressions.AggregateFunction(Name:="CountDistinct", Description:="Defines an aggregate function to count distinct values.")> _
Public Class CountDistinctAggregate
    Implements Telerik.Reporting.Expressions.IAggregateFunction
 
    Private distinctValues As System.Collections.Generic.List(Of Object)
 
    ''' <summary>
    ''' Initializes the current aggregate function to its initial state
    ''' ready to accumulate and merge values.
    ''' </summary>
    ''' <remarks>
    ''' This method is called every time the accumulation of values must
    ''' start over for a new subset of records from the data source.
    ''' </remarks>
    Sub Init() Implements Expressions.IAggregateFunction.Init
        Me.distinctValues = New System.Collections.Generic.List(Of Object)()
    End Sub
 
    ''' <summary>
    ''' Accumulates new argument values to the current aggregate function.
    ''' </summary>
    ''' <remarks>
    ''' This aggregate function accepts one argument:
    ''' number - a numeric value to accumulate to the aggregate function;
    ''' </remarks>
    Sub Accumulate(ByVal values() As Object) Implements Expressions.IAggregateFunction.Accumulate
 
        If Not distinctValues.Contains(values(0)) Then
            distinctValues.Add(values(0))
        End If
    End Sub
 
 
    ''' <summary>
    ''' Merges the specified aggregate function to the current one.
    ''' </summary>
    ''' <param name="Aggregate">
    ''' Specifies an aggregate function to be merged to the current one.
    ''' </param>
    ''' <remarks>
    ''' This method allows the reporting engine to merge two accumulated
    ''' subsets of the same aggregate function into a single result.
    ''' </remarks>
    Sub Merge(ByVal aggregate As Expressions.IAggregateFunction) Implements Expressions.IAggregateFunction.Merge
        ' Accumulate the values of the specified aggregate function.
        Dim sums1 = DirectCast(aggregate, CountDistinctAggregate).distinctValues
        For Each o As Object In sums1
            Me.Accumulate(New Object() {o})
        Next
    End Sub
 
    ''' <summary>
    ''' Returns the currently accumulated value of the aggregate function.
    ''' </summary>
    ''' <returns>
    ''' The currently accumulated numeric value of the aggregate function.
    ''' </returns>
    Function GetValue() As Object Implements Expressions.IAggregateFunction.GetValue
        Return Me.distinctValues.Count
    End Function
End Class


Using the Custom Aggregate in a Report
Apply AggregateFunctionAttribute to the custom aggregate class implementation to define an interface for the users of the aggregate function. The Name parameter of the attribute defines how to refer to the function in expressions.

And here is what our report might look like. The data is sample. You can play around with the sample attached report:


Comments

If you'd like to comment on this KB article, please, send us a Support Ticket.
Thank you!

Please Sign In to rate this article.