Практическое руководство. Вызов определенных моделью функций как методов объектов

В данном разделе описывается, как вызвать определяемую в модели функцию в качестве метода для объекта ObjectContext или в качестве статического метода для пользовательского класса. Определяемая моделью функция — это функция , определенная в концептуальной модели. В данном разделе показываются процедуры вызова этих функций напрямую, а не с помощью запросов LINQ to Entities. Сведения о вызове определяемых моделью функций в запросах LINQ to Entity см. в статье "Практическое руководство. Вызов определяемых моделью функций в запросах".

Если определяемая в модели функция вызвается как метод ObjectContext или как статический метод для пользовательского класса, в первую очередь необходимо сопоставить метод с определямой в модели функцией с EdmFunctionAttribute. Если метод определяется для класса ObjectContext, то следует использовать свойство QueryProvider для предоставления поставщика LINQ, однако, если статический метод определяется для пользовательского класса, то следует использовать свойство Provider для предоставления поставщика LINQ. Дополнительные сведения см. в примерах, приведенных после указанных ниже процедур.

В следующих процедурах описываются высокоуровневые структуры для вызова определяемой в модели функции в качестве метода для объекта ObjectContext или в качестве статического метода для пользовательского класса. В следующих примерах подробно описаны шаги данной процедуры. Эта процедура предполагает, что функция была определена в концептуальной модели. Дополнительные сведения см. в разделе "Практическое руководство. Определение пользовательских функций в концептуальной модели".

Вызов определяемой в модели функции в качестве метода объекта ObjectContext

  1. Добавьте исходный файл, чтобы расширить разделяемый класс, производный от класса ObjectContext, автоматически созданный средствами платформы Entity Framework. Если заглушка CLR определена в отдельном исходном файле, это поможет предотвратить потерю изменений при повторном создании файла.

  2. Добавьте к классу ObjectContext метод среды CLR, выполняющий следующие действия:

    • Устанавливает сопоставление с функцией, определяемой в концептуальной модели. Для сопоставления метода к нему необходимо применить атрибут EdmFunctionAttribute. Обратите внимание, что параметры атрибута NamespaceName и FunctionName представляют собой имя пространства имен концептуальной модели и имя функции концептуальной модели соответственно. При разрешении имени функции для LINQ учитывается регистр.

    • Возвращает результаты метода Execute, возвращаемого свойством QueryProvider.

  3. Вызовите метод в качестве элемента экземпляра класса ObjectContext.

Вызов определяемой в модели функции в качестве статического метода из пользовательского класса

  1. Добавьте к приложению класс со статическим методом, выполняющий следующие действия:

    • Устанавливает сопоставление с функцией, определяемой в концептуальной модели. Для сопоставления метода к нему необходимо применить атрибут EdmFunctionAttribute. Обратите внимание, что параметры атрибута NamespaceName и FunctionName представляют собой имя пространства имен концептуальной модели и имя функции концептуальной модели соответственно.

    • Принимает аргумент 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>). Рассмотрите описанную ниже функцию концептуальной модели, возвращающую подробные сведения 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

См. также