如何:将模型定义函数作为对象方法调用 (LINQ to Entities)
本主题介绍如何将模型定义函数作为 ObjectContext 对象的方法调用或作为自定义类的静态方法调用。 模型定义函数**是在概念模型中定义的函数。 本主题中的过程介绍如何直接调用这些函数,而不是从 LINQ to Entities 查询中调用它们。 有关在 LINQ to Entities 查询中调用模型定义函数的信息,请参阅如何:在查询中调用模型定义函数 (LINQ to Entities)。
无论您是将模型定义函数作为 ObjectContext 方法调用,还是作为自定义类的静态方法调用,首先都必须使用 EdmFunctionAttribute 将该方法映射到模型定义函数。 但是,当您定义 ObjectContext 类的方法时,必须使用 QueryProvider 属性公开 LINQ 提供程序,而当您定义自定义类的静态方法时,必须使用 Provider 属性公开 LINQ 提供程序。 有关更多信息,请参见下述过程后面的示例。
下面的这些过程高度概括了将模型定义函数作为 ObjectContext 对象的方法调用和作为自定义类的静态方法调用的信息。 后面的示例提供了有关这些过程中各个步骤的更多详细信息。 这些过程假定您在概念模型中定义了一个函数。 有关更多信息,请参见How to: Define Custom Functions in the Conceptual Model。
将模型定义函数作为 ObjectContext 对象的方法调用
添加一个源文件,以扩展派生自 ObjectContext 类(该类由实体框架工具自动生成)的分部类。 在单独的源文件中定义 CLR 存根可防止在重新生成文件时丢失所做的更改。
将一个公共语言运行时 (CLR) 方法添加到 ObjectContext 类,该方法可执行以下操作:
映射到在概念模型中定义的函数。 若要映射方法,必须将 EdmFunctionAttribute 应用于此方法。 请注意,此特性的 NamespaceName 和 FunctionName 参数分别是概念模型的命名空间名称和概念模型中的函数名称。 LINQ 的函数名称解析区分大小写。
返回由 QueryProvider 属性返回的 Execute 方法的结果。
将此方法作为 ObjectContext 类的实例的一个成员调用。
将模型定义函数作为自定义类的静态方法调用
向应用程序添加一个类,该类带有一个静态方法,可执行以下操作:
映射到在概念模型中定义的函数。 若要映射方法,必须将 EdmFunctionAttribute 应用于此方法。 请注意,此特性的 NamespaceName 和 FunctionName 参数分别是概念模型的命名空间名称和概念模型中的函数名称。
接受 IQueryable 参数。
返回由 Provider 属性返回的 Execute 方法的结果。
将此方法作为自定义类的一个静态成员调用
示例
将模型定义函数作为 ObjectContext 对象的一个方法调用
下面的示例演示如何将模型定义函数作为 ObjectContext 对象的一个方法调用。 此示例使用 AdventureWorks 销售模型。
请考虑下面的概念模型函数,它可返回指定产品的产品收入。 (有关向概念模型添加函数的信息,请参见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>
下面的代码向 AdventureWorksEntities 类添加了一个方法,该方法映射到上述的概念模型函数。
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
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))));
}
}
下面的代码调用上面的方法,以显示指定产品的产品收入:
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
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
int productId = 776;
Console.WriteLine(AWEntities.GetProductRevenue(productId));
}
下面的示例演示如何调用一个返回集合(作为 IQueryable 对象)的模型定义函数。 请考虑下面的概念模型函数,它可返回给定产品 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>
下面的代码向 AdventureWorksEntities 类添加了一个方法,该方法映射到上述的概念模型函数。
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
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))));
}
}
下面的代码示例调用此方法。 请注意,返回的 IQueryable 查询将进一步优化,以返回每个 SalesOrderDetail 的行合计。
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
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);
}
}
将模型定义函数作为自定义类的静态方法调用
下一个示例演示如何将模型定义函数作为自定义类的静态方法调用。 此示例使用 AdventureWorks 销售模型。
注意: |
---|
当您将模型定义函数作为自定义类的静态方法调用时,此模型定义函数必须接受集合且在集合中返回值的聚合。 |
请考虑下面的概念模型函数,它可返回 SalesOrderDetail 集合的产品收入。 (有关向概念模型添加函数的信息,请参见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>
下面的代码向应用程序添加了一个类,该类包含一个映射到上述概念模型函数的静态方法。
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
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>))));
}
}
下面的代码调用上面的方法,以显示指定 SalesOrderDetail 集合的产品收入:
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
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));
}
另请参见
概念
LINQ to Entities 中的查询
调用 LINQ to Entities 查询中的函数