This is a migrated thread and some comments may be shown as answers.

Custom Aggregate Not Working Like Examples

3 Answers 260 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Ed Lance
Top achievements
Rank 1
Ed Lance asked on 23 Oct 2012, 12:24 AM
I'm trying my hand at a custom aggregate class.  The report is bound directly to the datasource, and I put a text box in the report footer using the custom aggregate.  I was expecting the class to be instantiated once and accumulate values like all the examples show.  But in tracing the code execution in VS, I find that a new instance of the class is instantiated for every row in the dataset, meaning that no actual accumlation happens in the Accumulate method. 
The report has two levels of grouping, and I tried moving the text box to the footer of the inner group to see if it was an issue with being on the report footer.  No difference.

Can someone from Telerik please explain this?  Seems like if the function is called at the report level, there should be one instance of the class that accumulates the values for the whole bound data set.  Otherwise, all the code examples you have wouldn't work (i.e. this: http://blogs.telerik.com/blogs/posts/10-04-29/dynamic-sorting-of-reporting-crosstabs-using-a-custom-aggregate-function.aspx ) because the accumulation is actually held in a class level variable.

I'm pretty confused.

3 Answers, 1 is accepted

Sort by
0
Peter
Telerik team
answered on 25 Oct 2012, 05:19 PM
Hi Ed,

Multiple instances of the aggregate are created according to the report's data scopes. Data scopes are determined from the data items and groups in the report definition including: Report with Report groups and the Detail section, Table and Crosstab items with Table group and the Chart item. 

Aggregate function implementation accumulates values from each row using the Accumulate method. Then the function merges its value with other instances of the aggregate using the Merge method. Finally the function returns value using the GetValue method.

Thus you should correctly implement all of the interface methods in order the aggregate to work correctly and merge the aggregate instances. Generally we will appreciate if you elaborate further on your requirements and the aggregate you want to implement. Additionally we will appreciate if you send us your implementation.

Regards,
Peter
the Telerik team

HAPPY WITH TELERIK REPORTING? Do you feel that it is fantastic? Or easy to use? Or better than Crystal Reports? Tell the world, and help fellow developers! Write a short review about Telerik Reporting and Telerik Report Designer in Visual Studio Gallery today!

0
Ed Lance
Top achievements
Rank 1
answered on 26 Oct 2012, 09:10 PM
Sorry, didn't have a lot of time to get that report done.  For now, I solved the issue with some clever SQL.

The report was bound to the data source, there are two levels of grouping, and totals in the report footer.  The code is below.  When I used this aggregate in a group footer or report footer, an instance would be created for every record in the data source, so the logic in the Accumulate method wasn't able to work properly.

Here is the code.  The  report is already changed so I would have to create another sample report to send it to you.

Imports Telerik.Reporting.Expressions
 
<AggregateFunction(Description:="Sums the First value in the series", Name:="SumofFirst")> _
Public Class SumofFirst
    Implements IAggregateFunction
 
    Public mresult As Decimal
    Private mlast As Decimal = 0
 
    Public Sub Accumulate(ByVal values As Object()) Implements IAggregateFunction.Accumulate
        ' The aggregate function expects one parameter
        Dim value As Object = values(0)
 
        ' null values are not aggregated
        If value Is Nothing Then
            Return
        End If
 
        Dim dvalue As Decimal
        ' The actual accumulation
        If Decimal.TryParse(value, dvalue) Then
            If dvalue <> mlast Then
                mresult += dvalue
                mlast = dvalue
            End If
        End If
 
    End Sub
 
    Public Function GetValue() As Object Implements IAggregateFunction.GetValue
        Return Me.mresult
    End Function
 
    Public Sub Init() Implements IAggregateFunction.Init
        ' Add aggregate function initialization code here if needed
        Me.mresult = 0
    End Sub
 
    Public Sub Merge(ByVal aggregateFunction As IAggregateFunction) Implements IAggregateFunction.Merge
        Dim aggregate As SumofFirst = DirectCast(aggregateFunction, SumofFirst)
 
        Me.mresult += aggregate.mresult
 
    End Sub
End Class

0
Peter
Telerik team
answered on 31 Oct 2012, 04:32 PM
Hello Ed,

Yes you have correctly find out that we create an aggregate instance for every processing detail and group instance. Generally the main logic for determining the series uniqueness should participate in the Merge method also, because an aggregate instance will be created for the groups instance and while merging the details you can compare the series values.

Try debugging the Merge method in your aggregate class and when hit, this will be the instance created for the group data member.

See also:
User Aggregate Functions
Expression scope


All the best,
Peter
the Telerik team

HAPPY WITH TELERIK REPORTING? Do you feel that it is fantastic? Or easy to use? Or better than Crystal Reports? Tell the world, and help fellow developers! Write a short review about Telerik Reporting and Telerik Report Designer in Visual Studio Gallery today!

Tags
General Discussions
Asked by
Ed Lance
Top achievements
Rank 1
Answers by
Peter
Telerik team
Ed Lance
Top achievements
Rank 1
Share this question
or