次の方法で共有


方法: Model-Defined 関数をオブジェクト メソッドとして呼び出す

このトピックでは、モデル定義関数を ObjectContext オブジェクトのメソッドとして、またはカスタム クラスの静的メソッドとして呼び出す方法について説明します。 モデル定義関数は、概念モデルで定義される関数です。 このトピックの手順では、LINQ to Entities クエリから関数を呼び出す代わりに、これらの関数を直接呼び出す方法について説明します。 LINQ to Entities クエリでモデル定義関数を呼び出す方法については、「 方法: クエリで Model-Defined 関数を呼び出す」を参照してください。

モデル定義関数を ObjectContext メソッドとして呼び出す場合でも、カスタム クラスの静的メソッドとして呼び出す場合でも、まず、 EdmFunctionAttributeを使用してモデル定義関数にメソッドをマップする必要があります。 ただし、 ObjectContext クラスでメソッドを定義する場合は、 QueryProvider プロパティを使用して LINQ プロバイダーを公開する必要があります。一方、カスタム クラスで静的メソッドを定義する場合は、 Provider プロパティを使用して LINQ プロバイダーを公開する必要があります。 詳細については、以下の手順に従う例を参照してください。

次の手順では、モデル定義関数を ObjectContext オブジェクトのメソッドとして、およびカスタム クラスの静的メソッドとして呼び出すための概要を示します。 以下の例では、手順の詳細を示します。 この手順では、概念モデルで関数を定義していることを前提としています。 詳細については、「 方法: 概念モデルでカスタム関数を定義する」を参照してください。

ObjectContext オブジェクトのメソッドとしてモデル定義関数を呼び出すには

  1. ソース ファイルを追加して、Entity Framework ツールによって自動生成された、 ObjectContext クラスから派生した部分クラスを拡張します。 別のソース ファイルで CLR スタブを定義すると、ファイルの再生成時に変更が失われるのを防ぐことができます。

  2. 次の処理を行う共通言語ランタイム (CLR) メソッドを ObjectContext クラスに追加します。

    • 概念モデルで定義されている関数にマップされます。 メソッドをマップするには、メソッドに EdmFunctionAttribute を適用する必要があります。 属性の NamespaceName パラメーターと FunctionName パラメーターは、概念モデルの名前空間名と、概念モデルの関数名であることに注意してください。 LINQ の関数名解決では、大文字と小文字が区別されます。

    • Execute プロパティによって返されるQueryProvider メソッドの結果を返します。

  3. ObjectContext クラスのインスタンスのメンバーとしてメソッドを呼び出します。

カスタム クラスでモデル定義関数を静的メソッドとして呼び出すには

  1. 次の処理を行う静的メソッドを使用して、クラスをアプリケーションに追加します。

    • 概念モデルで定義されている関数にマップされます。 メソッドをマップするには、メソッドに EdmFunctionAttribute を適用する必要があります。 属性の NamespaceName パラメーターと FunctionName パラメーターは、概念モデルの名前空間名と、概念モデルの関数名であることに注意してください。

    • IQueryable引数を受け入れます。

    • Execute プロパティによって返されるProvider メソッドの結果を返します。

  2. カスタム クラスの静的メソッドをメンバーとしてメソッドを呼び出す

例 1

ObjectContext オブジェクト上のメソッドとしてモデル定義関数を呼び出す

次の例では、モデル定義関数を ObjectContext オブジェクトのメソッドとして呼び出す方法を示します。 この例では、 AdventureWorks Sales 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>

例 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

カスタム クラスの静的メソッドとして Model-Defined 関数を呼び出す

次の例では、モデル定義関数をカスタム クラスの静的メソッドとして呼び出す方法を示します。 この例では、 AdventureWorks Sales Model を使用します。

モデル定義関数をカスタム クラスの静的メソッドとして呼び出す場合、モデル定義関数はコレクションを受け入れ、コレクション内の値の集計を返す必要があります。

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

こちらも参照ください