How can I Implement My Own Native Aggregate Functions?

Please provide some more information on ISupportNativeAggregateFunctions and NativeAggregation

The designer manual mentions the NativeMin, NativeMax functions, which I needed. First of all the manual doesn’t mention that these Native*-function only show up if the data provider implements the ISupportNativeAggregateFunctions interface. As they only show up, depending of the used data provider, there should be for every Native*() function an link to a short description.

Then I found Lightning Fast Aggregations for .NET | Reporting Blog List & Label which mentions the custom data provider and support for ISupportNativeAggregateFunctions. I searched for a sample Search · ISupportNativeAggregateFunctions · GitHub but there is none.

So I started to play around. The documentation in the LL .Net help is very scarce!

After implementing the ISupportNativeAggregateFunctions interface at my table implementation, NativeMax() and NativeMin() where available in the designer.

But when using for example NativeMax(Artikel.Basispreis) in the expression editor I get some messages from the designer that the expression is not valid.

My current implementation looks like this:

#region ISupportNativeAggregateFunctions
public object ExecuteNativeAggregateFunction(ExecuteNativeAggregateFunctionArguments args)
{
    object value = 0;

    return value ; // throw new NotImplementedException();
}

public bool CheckNativeAggregateFunctionSyntax(CheckNativeAggregateFunctionSyntaxArguments args)
{
    bool isChecked = false;

    return isChecked; // throw new NotImplementedException();
}

public bool SupportsNativeAggregateFunction(NativeAggregateFunction function)
{
    bool isSupported = false;

    if (function == NativeAggregateFunction.Min || function == NativeAggregateFunction.Max)
        isSupported = true;

    return isSupported;
}
#endregion

SupportsNativeAggregateFunction is called and NativeMin and NativeMax are available afterwards, but CheckNativeAggregateFunctionSyntax and ExecuteNativeAggregateFunction are never called. Is there some other Interface which is required for ISupportNativeAggregateFunctions to work properly?

Moved this from Idea Place to general discussion as it seems more suitable (and you will get replies faster).

Your mockup looks right, make sure to implement the interface on the same object that implements the ITable interface. Can you confirm that this is where you’ve added the interface to?

Yes I can confirm that the interface is implemented with ITable

class ArtikelListTable : ITable, IEnumerable<ITableRow>, ISupportNativeAggregateFunctions

Do I have to support filters, sorting, schemaRow or something like this to get NativeAggregate get going?

Currently I get this error:

Would it be possible to send the code of your custom provider for further analysis (e.g. via a support case)? Alternatively, I could provide the component’s sources to you so you can debug on your end?

I created support case W202012150002 with a sample of your CSV-dataprovider.

1 Like

Just had a deeper look. Apologies, your guess was right and you need to implement the IAdvancedFiltering interface on the class which is less than obvious. However, the reason is simple once you dig into it, the parameter could be a complex expression which the database engine needs to be capable of processing in order to be able to work with it natively. As the filter translation mechanism can be used to translate LL functions to native functions, this mechanism is reused, meaning you’ll get the function parameter translated to native syntax into the native aggregate evaluation.

Back to your simple sample where you would just need to get the field name into the evaluation this would be easy: just add the IAdvancedFiltering to your ITable class and make the implementation read

public void ApplyAdvancedFilter(string filter, object[] parameters)
{
    // filtering not really supported, interface is needed for native aggregates
    return;
}

public object TranslateFilterSyntax(LlExpressionPart part, ref object name, int argumentCount, object[] arguments)
{
    switch(part)
    {
        case LlExpressionPart.Field:
            if (arguments[0] == null)
                return null;
            // just make sure the field belongs to this table and is not a 1:1 field
            string fieldName = arguments[0].ToString();
            if (!fieldName.StartsWith(TableName + ".") || fieldName.Contains("@"))
            {
                return null;
            }
            // if basic sanity checks are okay, just return the field name here
            return fieldName;
        default:
            return null;
    }
}

This will not actually do any filtering which is fine as LL always applies its filter additionally. And it will simply translate the field name to the very same field name, meaning you’ll get exactly this as parameter for the CheckNativeAggregateFunctionSyntax and ExecuteNativeAggregateFunction interface methods.

I admit this is heavy stuff, we’ll probably have better documentation for this interface in the future. Feel free to reach out here or via support if anything else is needed. Attaching the updated CsvDataProvider here.

CsvDataProvider.cs (23.7 KB)

Also, here’s another implementation for this interface, this time from the ADO.NET data provider. I’m also leaving the IAdvancedFiltering implementation in place. This file will not compile but might still be a useful reference:

lladodataproviders.cs (11.6 KB)