Skip to main content
.NET 6.0+

How to: Implement a Custom Criteria Language Function Operator

  • 5 minutes to read

While XPO supports a number of built-in criteria language operators, you may need additional function operators either for complex calculations or in cases when you want to exploit certain database-specific functions. This topic demonstrates how to implement the MyGetMonth function (similar to the built-in FunctionOperatorType.GetMonth function) based on the DATEPART function supported by the Microsoft Access database engine. The MyGetMonth function returns the month part (as a number) of a specified date.

First, declare the MyGetMonthFunction class as the implementor of the ICustomFunctionOperatorFormattable interface.

Important

Do not use the function name that starts with Is if this function does not return a Boolean value. It may lead to unexpected results.

using System;
using DevExpress.Data.Filtering;
using DevExpress.Xpo.DB;

// ...
public class MyGetMonthFunction : ICustomFunctionOperatorFormattable {
    #region ICustomFunctionOperatorFormattable Members
    // The function's expression to be evaluated on the server.
    string ICustomFunctionOperatorFormattable.Format(Type providerType, params string[] operands) {
        // This example implements the function for Microsoft Access databases only.
        if (providerType == typeof(AccessConnectionProvider))
            return string.Format("datepart(\"m\", {0})", operands[0]);
        throw new NotSupportedException(string.Concat(
            "This provider is not supported: ", providerType.Name));
    }

    public static int MyGetMonth(DateTime date) {
        return date.Month;
    }
    #endregion

    #region ICustomFunctionOperator Members
    // Evaluates the function on the client.
    object ICustomFunctionOperator.Evaluate(params object[] operands) {
        return MyGetMonth((DateTime)operands[0]);
    }

    string ICustomFunctionOperator.Name {
        get { return nameof(MyGetMonth); }
    }

    Type ICustomFunctionOperator.ResultType(params Type[] operands) {
        return typeof(int);
    }
    #endregion
}

The next step is to register the custom function. Previously, you had to pass a custom function to a data store provider’s RegisterCustomFunctionOperator method and a dictionary’s XPDictionary.CustomFunctionOperators collection to accomplish this. Starting with v2011 vol 1, you can call the CriteriaOperator.RegisterCustomFunction or CriteriaOperator.RegisterCustomFunctions method instead.

Modify the project’s Main method as shown below. In Visual Basic, add a module to the project, create the Main method and set it as the startup object via the project’s properties.

using System;
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.Metadata;
using DevExpress.Data.Filtering;

static class Program {
    static void Main() {
        ConnectionProviderSql provider = 
            (ConnectionProviderSql)XpoDefault.GetConnectionProvider(
            AccessConnectionProvider.GetConnectionString(@"..\..\CustomFunction.mdb"),
            AutoCreateOption.DatabaseAndSchema);
        XPDictionary dict = new ReflectionDictionary();

        // New registration technique.
        CriteriaOperator.RegisterCustomFunction(new MyGetMonthFunction());

        // Outdated registration technique.
        // provider.RegisterCustomFunctionOperator(new MyGetMonthFunction());
        // dict.CustomFunctionOperators.Add(new MyGetMonthFunction());

        // Instantiating a DAL.
        XpoDefault.DataLayer = new SimpleDataLayer(dict, provider);
        XpoDefault.Session = null;
        // ...
    }
}

After a data access layer has been instantiated, you can use the implemented custom function operator to build filter criteria and expressions.

static class Program {
    static void Main() {
        // ...
        using (Session session = new Session()) {
            // Using MyGetMonth to build criteria.
            CriteriaOperator criteria = CriteriaOperator.Parse("MyGetMonth(OrderDate) = 5");
            // Applying criteria to filter XPView contents.
            XPView view = new XPView(session, typeof(Order), "OrderDate", criteria);
            // Using MyGetMonth in an XPView column's expression.
            view.AddProperty("Month", "MyGetMonth(OrderDate)");

            foreach (ViewRecord prop in view) {
                Console.WriteLine(prop["OrderDate"]);
                Console.WriteLine("Month: " + prop["Month"]);
            }
        }
        Console.WriteLine("done\npress any key to exit ..");
        Console.ReadKey();
    }
}

To learn how to implement custom functions and criteria, and use them in LINQ to XPO expressions, see How to: Implement Custom Functions and Criteria in LINQ to XPO.

See Also