Поделиться через


Как вызывать функции, определяемые в модели, в качестве методов объекта (язык 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

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

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

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

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

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

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

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

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

    • Принимает аргумент IQueryable.

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

  2. Вызовите метод в качестве члена статического метода из пользовательского класса

Пример

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

В приведенном ниже примере показано, как вызвать определяемую в модели функцию в качестве метода для объекта ObjectContext. В примере используется модель AdventureWorks Sales.

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

Dd456845.note(ru-ru,VS.100).gifПримечание
Если определяемая в модели функция вызывается как статический метод для пользовательского класса, эта функция должна принять коллекцию и вернуть результат статистической обработки значений из коллекции.

Рассмотрите описанную ниже функцию концептуальной модели, возвращающую доход от коллекции 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

Другие ресурсы

.edmx File Overview