如何:调用模型定义的函数作为对象方法

本主题介绍如何将模型定义函数作为 ObjectContext 对象的方法调用或作为自定义类的静态方法调用。 模型定义函数是在概念模型中定义的函数。 本主题中的过程介绍如何直接调用这些函数,而不是从 LINQ to Entities 查询中调用它们。 有关在 LINQ to Entities 查询中调用模型定义函数的信息,请参阅如何:在查询中调用模型定义函数

无论您是将模型定义函数作为 ObjectContext 方法调用,还是作为自定义类的静态方法调用,首先都必须使用 EdmFunctionAttribute 将该方法映射到模型定义函数。 但是,当您定义 ObjectContext 类的方法时,必须使用 QueryProvider 属性公开 LINQ 提供程序,而当您定义自定义类的静态方法时,必须使用 Provider 属性公开 LINQ 提供程序。 有关更多信息,请参见下述过程后面的示例。

下面的这些过程高度概括了将模型定义函数作为 ObjectContext 对象的方法调用和作为自定义类的静态方法调用的信息。 后面的示例提供了有关这些过程中各个步骤的更多详细信息。 这些过程假定您在概念模型中定义了一个函数。 有关详细信息,请参阅如何:在概念模型中定义自定义函数

将模型定义函数作为 ObjectContext 对象的方法调用

  1. 添加一个源文件,以扩展派生自 ObjectContext 类(该类由实体框架工具自动生成)的分部类。 在单独的源文件中定义 CLR 存根可防止在重新生成文件时丢失所做的更改。

  2. 将一个公共语言运行时 (CLR) 方法添加到 ObjectContext 类,该方法可执行以下操作:

    • 映射到在概念模型中定义的函数。 若要映射方法,必须将 EdmFunctionAttribute 应用于此方法。 请注意,此特性的 NamespaceNameFunctionName 参数分别是概念模型的命名空间名称和概念模型中的函数名称。 LINQ 的函数名称解析区分大小写。

    • 返回由 Execute 属性返回的 QueryProvider 方法的结果。

  3. 将此方法作为 ObjectContext 类的实例的一个成员调用。

将模型定义函数作为自定义类的静态方法调用

  1. 向应用程序添加一个类,该类带有一个静态方法,可执行以下操作:

    • 映射到在概念模型中定义的函数。 若要映射方法,必须将 EdmFunctionAttribute 应用于此方法。 请注意,此特性的 NamespaceNameFunctionName 参数分别是概念模型的命名空间名称和概念模型中的函数名称。

    • 接受 IQueryable 自变量。

    • 返回由 Execute 属性返回的 Provider 方法的结果。

  2. 将此方法作为自定义类的一个静态成员调用

示例 1

将模型定义函数作为 ObjectContext 对象的一个方法调用

下面的示例演示如何将模型定义函数作为 ObjectContext 对象的一个方法调用。 此示例使用 AdventureWorks 销售模型

请考虑下面的概念模型函数,它可返回指定产品的产品收入。 (有关将函数添加到概念模型的信息,请参阅如何:在概念模型中定义自定义函数。)

<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>

示例 2

下面的代码向 AdventureWorksEntities 类添加了一个方法,该方法映射到上述的概念模型函数。

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

示例 3

下面的代码调用上面的方法,以显示指定产品的产品收入:

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

示例 4

下面的示例演示如何调用一个返回集合(作为 IQueryable<T> 对象)的模型定义函数。 请考虑下面的概念模型函数,它可返回给定产品 ID 的所有 SalesOrderDetails

<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>

示例 5

下面的代码向 AdventureWorksEntities 类添加了一个方法,该方法映射到上述的概念模型函数。

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

示例 6

下面的代码示例调用此方法。 请注意,返回的 IQueryable<T> 查询将进一步优化,以返回每个 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

示例 7

将模型定义函数作为自定义类的静态方法调用

下一个示例演示如何将模型定义函数作为自定义类的静态方法调用。 此示例使用 AdventureWorks 销售模型

备注

当您将模型定义函数作为自定义类的静态方法调用时,此模型定义函数必须接受集合且在集合中返回值的聚合。

请考虑下面的概念模型函数,它可返回 SalesOrderDetail 集合的产品收入。 (有关将函数添加到概念模型的信息,请参阅如何:在概念模型中定义自定义函数。)

<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>

示例 8

下面的代码向应用程序添加了一个类,该类包含一个映射到上述概念模型函数的静态方法。

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

示例 9

下面的代码调用上面的方法,以显示指定 SalesOrderDetail 集合的产品收入:

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

请参阅