Cómo: Llamar a funciones definidas por el modelo como métodos de objeto (LINQ to Entities)

En este tema se describe cómo llamar a una función definida por el modelo como un método en un objeto ObjectContext o como un método estático en una clase personalizada. Una función definida por el modelo es una función que se define en el modelo conceptual. Los procedimientos de este tema describen cómo llamar directamente a estas funciones en lugar de hacerlo desde consultas LINQ to Entities. Para obtener información sobre cómo llamar a las funciones definidas por el modelo en consultas LINQ to Entities, vea Cómo: Llamar a funciones definidas por el modelo en consultas (LINQ to Entities).

Tanto si se llama a una función definida por el modelo como un método ObjectContext o como un método estático en una clase personalizada, primero se deberá asignar el método a dicha función con un atributo EdmFunctionAttribute. Sin embargo, si se define un método en la clase ObjectContext, se debe usar la propiedad QueryProvider para exponer el proveedor LINQ, mientras que si se define un método estático en una clase personalizada, se debe usar la propiedad Provider para exponer dicho proveedor. Para obtener más información, vea los ejemplos que aparecen a continuación de los procedimientos siguientes.

Los procedimientos siguientes proporcionan esquemas generales para llamar a una función definida por el modelo como un método en un objeto ObjectContext y como un método estático en una clase personalizada. Los ejemplos que los siguen proporcionan más detalles sobre los pasos de los procedimientos. Los procedimientos dan por hecho que se ha definido una función en el modelo conceptual. Para obtener más información, vea How to: Define Custom Functions in the Conceptual Model.

Para llamar a una función definida por el modelo como un método en un objeto ObjectContext

  1. Agregue un archivo de código fuente para extender la clase parcial derivada de la clase ObjectContext, generada automáticamente por las herramientas de Entity Framework. La definición del código auxiliar de CLR en un archivo de código fuente independiente evitará que se pierdan los cambios cuando se regenere el archivo.

  2. Agregue un método de Common Language Runtime (CLR) a la clase ObjectContext que haga lo siguiente:

    • Se asigne a la función definida en el modelo conceptual. Para asignar el método, debe aplicarle un atributo EdmFunctionAttribute. Tenga en cuenta que los parámetros NamespaceName y FunctionName del atributo son el nombre del espacio de nombres del modelo conceptual y el nombre de la función en el modelo conceptual, respectivamente. La resolución del nombre de la función para LINQ distingue entre mayúsculas y minúsculas.

    • Devuelva los resultados del método Execute devuelto por la propiedad QueryProvider.

  3. Llame al método como un miembro de una instancia de la clase ObjectContext.

Para llamar a una función definida por el modelo como un método estático en una clase personalizada

  1. Agregue una clase a la aplicación con un método estático que haga lo siguiente:

    • Se asigne a la función definida en el modelo conceptual. Para asignar el método, debe aplicarle un atributo EdmFunctionAttribute. Tenga en cuenta que los parámetros FunctionName y NamespaceName del atributo son el nombre del espacio de nombres del modelo conceptual y el nombre de la función en el modelo conceptual, respectivamente.

    • Acepte un argumento IQueryable.

    • Devuelva los resultados del método Execute devuelto por la propiedad Provider.

  2. Llame al método como un miembro de un método estático en la clase personalizada

Ejemplo

Llamar a una función definida por el modelo como un método en un objeto ObjectContext

En el siguiente ejemplo se muestra cómo llamar a una función definida por el modelo como un método en un objeto ObjectContext. En el ejemplo se usa el Modelo AdventureWorks Sales.

Observe la función de modelo conceptual siguiente que devuelve los ingresos obtenidos para un producto determinado. (Para obtener información sobre cómo agregar la función al modelo conceptual, vea 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>

El código siguiente agrega un método a la clase AdventureWorksEntities que se asigna a la función de modelo conceptual anterior.

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))));
    }
}

El código siguiente llama al método anterior para mostrar los ingresos obtenidos para un producto determinado:

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));
}

En el ejemplo siguiente se muestra cómo llamar a una función definida por el modelo que devuelve una colección (como un objeto IQueryable). Observe la función de modelo conceptual siguiente que devuelve todos los SalesOrderDetails para un identificador de producto determinado.

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

El código siguiente agrega un método a la clase AdventureWorksEntities que se asigna a la función de modelo conceptual anterior.

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))));
    }
}

El código siguiente llama al método. Observe que la consulta IQueryable devuelta se redefine para devolver los totales de línea para cada 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);
    }
}

Llamar a una función definida por el modelo como un método estático en una clase personalizada

En el ejemplo siguiente se muestra cómo llamar a una función definida por el modelo como un método estático en una clase personalizada. En el ejemplo se usa el Modelo AdventureWorks Sales.

Dd456845.note(es-es,VS.100).gifNota:
Cuando se llama a una función definida por el modelo como un método estático en una clase personalizada, la función debe aceptar una colección y devolver una agregación de valores de la colección.

Considere la función de modelo conceptual siguiente que devuelve los ingresos de los productos para una colección SalesOrderDetail. (Para obtener información sobre cómo agregar la función al modelo conceptual, vea 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>

El código siguiente agrega una clase a la aplicación que contiene un método estático que se asigna a la función de modelo conceptual anterior.

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>))));
    }
}

El código siguiente llama al método anterior para mostrar los ingresos de los productos para una colección 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));
}

Vea también

Conceptos

Consultas en LINQ to Entities
Llamar a funciones en consultas de LINQ to Entities

Otros recursos

.edmx File Overview