How to: Call Model-Defined Functions as Object Methods

This topic describes how to call a model-defined function as a method on an ObjectContext object or as a static method on a custom class. A model-defined function is a function that is defined in the conceptual model. The procedures in the topic describe how to call these functions directly instead of calling them from LINQ to Entities queries. For information about calling model-defined functions in LINQ to Entities queries, see How to: Call Model-Defined Functions in Queries.

Whether you call a model-defined function as an ObjectContext method or as a static method on a custom class, you must first map the method to the model-defined function with an EdmFunctionAttribute. However, when you define a method on the ObjectContext class, you must use the QueryProvider property to expose the LINQ provider, whereas when you define a static method on a custom class, you must use the Provider property to expose the LINQ provider. For more information, see the examples that follow the procedures below.

The procedures below provide high-level outlines for calling a model-defined function as a method on an ObjectContext object and as a static method on a custom class. The examples that follow provide more detail about the steps in the procedures. The procedures assume that you have defined a function in the conceptual model. For more information, see How to: Define Custom Functions in the Conceptual Model.

To call a model-defined function as a method on an ObjectContext object

  1. Add a source file to extend the partial class derived from the ObjectContext class, auto-generated by the Entity Framework tools. Defining the CLR stub in a separate source file will prevent the changes from being lost when the file is regenerated.

  2. Add a common language runtime (CLR) method to your ObjectContext class that does the following:

    • Maps to the function defined in the conceptual model. To map the method, you must apply an EdmFunctionAttribute to the method. Note that the NamespaceName and FunctionName parameters of the attribute are the namespace name of the conceptual model and the function name in the conceptual model, respectively. Function name resolution for LINQ is case sensitive.

    • Returns the results of the Execute method that is returned by the QueryProvider property.

  3. Call the method as a member on an instance of the ObjectContext class.

To call a model-defined function as static method on a custom class

  1. Add a class to your application with a static method that does the following:

    • Maps to the function defined in the conceptual model. To map the method, you must apply an EdmFunctionAttribute to the method. Note that the NamespaceName and FunctionName parameters of the attribute are the namespace name of the conceptual model and the function name in the conceptual model, respectively.

    • Accepts an IQueryable argument.

    • Returns the results of the Execute method that is returned by the Provider property.

  2. Call the method as a member a static method on the custom class

Example 1

Calling a Model-Defined Function as a Method on an ObjectContext Object

The following example demonstrates how to call a model-defined function as a method on an ObjectContext object. The example uses the AdventureWorks Sales Model.

Consider the conceptual model function below that returns product revenue for a specified product. (For information about adding the function to your conceptual model, see How to: Define Custom Functions in the Conceptual Model.)

<Function Name="GetProductRevenue" ReturnType="Edm.Decimal">
  <Parameter Name="productID" Type="Edm.Int32" />
  <DefiningExpression>
    SUM( SELECT VALUE((s.UnitPrice - s.UnitPriceDiscount)  * s.OrderQty)
    FROM AdventureWorksEntities.SalesOrderDetails as s
    WHERE s.ProductID = productID)
  </DefiningExpression>
</Function>

Example 2

The following code adds a method to the AdventureWorksEntities class that maps to the conceptual model function above.

public partial class AdventureWorksEntities : ObjectContext
{
    [EdmFunction("AdventureWorksModel", "GetProductRevenue")]
    public decimal? GetProductRevenue(int productId)
    {
        return this.QueryProvider.Execute<decimal?>(Expression.Call(
            Expression.Constant(this),
            (MethodInfo)MethodInfo.GetCurrentMethod(),
            Expression.Constant(productId, typeof(int))));
    }
}
Partial Public Class AdventureWorksEntities
    Inherits ObjectContext

    <EdmFunction("AdventureWorksModel", "GetProductRevenue")>
    Public Function GetProductRevenue(ByVal details As _
                    IQueryable(Of SalesOrderDetail)) As _
                    System.Nullable(Of Decimal)
        Return Me.QueryProvider.Execute(Of System.Nullable(Of Decimal)) _
            (Expression.[Call](Expression.Constant(Me), _
            DirectCast(MethodInfo.GetCurrentMethod(), MethodInfo), _
            Expression.Constant(details, GetType(IQueryable(Of SalesOrderDetail)))))
    End Function
End Class

Example 3

The following code calls the method above to display the product revenue for a specified product:

using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    int productId = 776;

    Console.WriteLine(AWEntities.GetProductRevenue(productId));
}
Using AWEntities As New AdventureWorksEntities()

    Dim productId As Integer = 776

    Dim details = From s In AWEntities.SalesOrderDetails _
                  Where s.ProductID = productId _
                  Select s

    Console.WriteLine(AWEntities.GetProductRevenue(details))
End Using

Example 4

The following example demonstrates how to call a model-defined function that returns a collection (as an IQueryable<T> object). Consider the conceptual model function below that returns all the SalesOrderDetails for a given product ID.

<Function Name="GetDetailsById" 
          ReturnType="Collection(AdventureWorksModel.SalesOrderDetail)">
  <Parameter Name="productID" Type="Edm.Int32" />
  <DefiningExpression>
    SELECT VALUE s
    FROM AdventureWorksEntities.SalesOrderDetails AS s
    WHERE s.ProductID = productID
  </DefiningExpression>
</Function>

Example 5

The following code adds a method to the AdventureWorksEntities class that maps to the conceptual model function above.

public partial class AdventureWorksEntities : ObjectContext
{
    [EdmFunction("AdventureWorksModel", "GetDetailsById")]
    public IQueryable<SalesOrderDetail> GetDetailsById(int productId)
    {
        return this.QueryProvider.CreateQuery<SalesOrderDetail>(Expression.Call(
            Expression.Constant(this),
            (MethodInfo)MethodInfo.GetCurrentMethod(),
            Expression.Constant(productId, typeof(int))));
    }
}
Partial Public Class AdventureWorksEntities
    Inherits ObjectContext
    <EdmFunction("AdventureWorksModel", "GetDetailsById")> _
    Public Function GetDetailsById(ByVal productId As Integer) _
            As IQueryable(Of SalesOrderDetail)
        Return Me.QueryProvider.CreateQuery(Of SalesOrderDetail) _
            (Expression.[Call](Expression.Constant(Me), _
             DirectCast(MethodInfo.GetCurrentMethod(), MethodInfo), _
             Expression.Constant(productId, GetType(Integer))))
    End Function
End Class

Example 6

The following code calls the method. Note that the returned IQueryable<T> query is further refined to return line totals for each SalesOrderDetail.

using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    int productId = 776;

    var lineTotals = AWEntities.GetDetailsById(productId).Select(d =>d.LineTotal);

    foreach(var lineTotal in lineTotals)
    {
        Console.WriteLine(lineTotal);
    }
}
Using AWEntities As New AdventureWorksEntities()
    Dim productId As Integer = 776

    Dim lineTotals = AWEntities.GetDetailsById(productId).[Select](Function(d) d.LineTotal)

    For Each lineTotal In lineTotals
        Console.WriteLine(lineTotal)
    Next

Example 7

Calling a Model-Defined Function as a Static Method on a Custom Class

The next example demonstrates how to call a model-defined function as a static method on a custom class. The example uses the AdventureWorks Sales Model.

Note

When you call a model-defined function as a static method on a custom class, the model-defined function must accept a collection and return an aggregation of values in the collection.

Consider the conceptual model function below that returns product revenue for a SalesOrderDetail collection. (For information about adding the function to your conceptual model, see How to: Define Custom Functions in the Conceptual Model.)

<Function Name="GetProductRevenue" ReturnType="Edm.Decimal">
  <Parameter Name="details" Type="Collection(AdventureWorksModel.SalesOrderDetail)" />
  <DefiningExpression>
    SUM( SELECT VALUE((s.UnitPrice - s.UnitPriceDiscount)  * s.OrderQty)
    FROM details as s)
  </DefiningExpression>
</Function>

Example 8

The following code adds a class to your application that contains a static method that maps to the conceptual model function above.

public class MyClass
{
    [EdmFunction("AdventureWorksModel", "GetProductRevenue")]
    public static decimal? GetProductRevenue(IQueryable<SalesOrderDetail> details)
    {
        return details.Provider.Execute<decimal?>(Expression.Call(
            (MethodInfo)MethodInfo.GetCurrentMethod(),
            Expression.Constant(details, typeof(IQueryable<SalesOrderDetail>))));
    }
}
Public Class [MyClass]
    <EdmFunction("AdventureWorksModel", "GetProductRevenue")> _
    Public Shared Function GetProductRevenue(ByVal details As _
                IQueryable(Of SalesOrderDetail)) As _
                System.Nullable(Of Decimal)
        Return details.Provider.Execute(Of System.Nullable(Of Decimal)) _
            (Expression.[Call](DirectCast(MethodInfo.GetCurrentMethod(), MethodInfo), _
            Expression.Constant(details, GetType(IQueryable(Of SalesOrderDetail)))))
    End Function
End Class

Example 9

The following code calls the method above to display the product revenue for a SalesOrderDetail collection:

using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    int productId = 776;

    var details = from s in AWEntities.SalesOrderDetails
                  where s.ProductID == productId select s;

    Console.WriteLine(MyClass.GetProductRevenue(details));
}
Using AWEntities As New AdventureWorksEntities()
    Dim productId As Integer = 776

    Dim details = From s In AWEntities.SalesOrderDetails _
                  Where s.ProductID = productId _
                  Select s

    Console.WriteLine([MyClass].GetProductRevenue(details))
End Using

See also