Comment : appeler des fonctions définies par modèle comme méthodes d'objet

Cette rubrique décrit comment appeler une fonction définie par modèle comme une méthode sur un objet ObjectContext ou comme une méthode statique sur une classe personnalisée. Une fonction définie par modèle est une fonction qui est définie dans le modèle conceptuel. Les procédures décrites dans cette rubrique montrent comment appeler directement ces fonctions au lieu de les appeler à partir de requêtes LINQ to Entities. Pour plus d’informations sur l’appel de fonctions définies par modèle dans les requêtes LINQ to Entities, consultez Procédure : Appeler des fonctions définies par modèle dans les requêtes.

Si vous appelez une fonction définie par modèle comme une méthode ObjectContext ou comme une méthode statique sur une classe personnalisée, vous devez mapper en premier la méthode à la fonction définie par modèle avec un attribut EdmFunctionAttribute. Toutefois, lorsque vous définissez une méthode sur la classe ObjectContext, vous devez utiliser la propriété QueryProvider pour exposer le fournisseur LINQ, alors que lorsque vous définissez une méthode statique sur une classe personnalisée, vous devez utiliser la propriété Provider pour exposer le fournisseur LINQ. Pour plus d'informations, consultez les exemples qui suivent les procédures ci-dessous.

Les procédures suivantes fournissent une présentation de haut niveau pour l'appel d'une fonction définie par modèle comme une méthode sur un objet ObjectContext et comme une méthode statique sur une classe personnalisée. Les exemples qui suivent fournissent plus de détail sur les étapes des procédures. Les procédures supposent que vous avez défini une fonction dans le modèle conceptuel. Pour plus d’informations, consultez Procédure : Définir des fonctions personnalisées dans le modèle conceptuel.

Pour appeler une fonction définie par modèle comme une méthode sur un objet ObjectContext

  1. Ajoutez un fichier source pour étendre la classe partielle dérivée de la classe ObjectContext, générée automatiquement par les outils Entity Framework. La définition du stub de CLR dans un fichier source distinct empêche la perte des modifications lorsque le fichier est régénéré.

  2. Ajoutez une méthode CLR (Common Language Runtime) à votre classe ObjectContext qui effectue les opérations suivantes :

    • Elle est mappée à la fonction définie dans le modèle conceptuel. Pour mapper la méthode, vous devez lui appliquer un attribut EdmFunctionAttribute. Notez que les paramètres NamespaceName et FunctionName de l'attribut correspondent au nom de l'espace de noms du modèle conceptuel et au nom de la fonction dans le modèle conceptuel, respectivement. La résolution des noms de fonctions pour LINQ respecte la casse.

    • Elle retourne les résultats de la méthode Execute retournée par la propriété QueryProvider.

  3. Appelez la méthode en tant que membre sur une instance de la classe ObjectContext.

Pour appeler une fonction définie par modèle comme une méthode statique sur une classe personnalisée

  1. Ajoutez une classe à votre application avec une méthode statique qui effectue les opérations suivantes :

    • Elle est mappée à la fonction définie dans le modèle conceptuel. Pour mapper la méthode, vous devez lui appliquer un attribut EdmFunctionAttribute. Notez que les paramètres NamespaceName et FunctionName de l'attribut correspondent au nom de l'espace de noms du modèle conceptuel et au nom de la fonction dans le modèle conceptuel, respectivement.

    • Elle accepte un argument IQueryable.

    • Elle retourne les résultats de la méthode Execute retournée par la propriété Provider.

  2. Appelez la méthode comme méthode statique sur la classe personnalisée.

Exemple 1

Appel d'une fonction définie par modèle comme une méthode sur un objet ObjectContext

L'exemple suivant montre comment appeler une fonction définie par modèle comme une méthode sur un objet ObjectContext. L’exemple utilise le modèle de vente AdventureWorks Sales Model.

Considérez la fonction de modèle conceptuel ci-dessous qui retourne le revenu généré par un produit donné. (Pour plus d’informations sur l’ajout de la fonction à votre modèle conceptuel, consultez Procédure : Définir des fonctions personnalisées dans le modèle conceptuel.)

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

Exemple 2

Le code suivant ajoute une méthode à la classe AdventureWorksEntities qui est mappée à la fonction de modèle conceptuel ci-dessus.

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

Exemple 3

Le code suivant appelle la méthode ci-dessus pour afficher le revenu généré par un produit donné :

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

Exemple 4

L’exemple suivant montre comment appeler une fonction définie par modèle qui retourne une collection (en tant qu’objet IQueryable<T>). Considérez la fonction de modèle conceptuel ci-dessous qui retourne tous les détails SalesOrderDetails pour un ID de produit donné.

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

Exemple 5

Le code suivant ajoute une méthode à la classe AdventureWorksEntities qui est mappée à la fonction de modèle conceptuel ci-dessus.

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

Exemple 6

Le code suivant appelle la méthode. Notez que la requête IQueryable<T> retournée est encore affinée pour retourner les totaux de ligne pour chaque 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

Exemple 7

Appel d'une fonction définie par modèle comme une méthode statique sur une classe personnalisée

L'exemple suivant montre comment appeler une fonction définie par modèle comme une méthode statique sur une classe personnalisée. L’exemple utilise le modèle de vente AdventureWorks Sales Model.

Notes

Lorsque vous appelez une fonction définie par modèle comme une méthode statique sur une classe personnalisée, la fonction définie par modèle doit accepter une collection et retourner une agrégation de valeurs dans la collection.

Considérez la fonction de modèle conceptuel ci-dessous, qui retourne le revenu produit pour une collection SalesOrderDetail. (Pour plus d’informations sur l’ajout de la fonction à votre modèle conceptuel, consultez Procédure : Définir des fonctions personnalisées dans le modèle conceptuel.)

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

Exemple 8

Le code suivant ajoute une classe à votre application qui contient une méthode statique mappée à la fonction de modèle conceptuel ci-dessus.

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

Exemple 9

Le code suivant appelle la méthode ci-dessus pour afficher le revenu produit pour une collection 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

Voir aussi