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


Формирование результатов запроса (Entity Framework)

При выполнении запроса возвращаются только те объекты, которые были специально затребованы в нем. Например, когда запрос к модели Adventure Works Sales Model возвращает объекты Customer, по умолчанию связанные объекты SalesOrderHeader не возвращаются, даже несмотря на наличие связи между объектами Customer и SalesOrderHeader. Благодаря этой особенности приложение всегда знает области данных, которые возвращаются при запросе объектов. По умолчанию всегда возвращаются объекты связей, которые представляют ассоциации между типами сущностей. Когда объекты формируются на основе концептуальной схемы модели EDM, свойства навигации формируются для объектов сущности в обоих окончаниях ассоциации. Данные свойства навигации возвращают либо EntityReference в элементе «один» взаимно-однозначной связи или связи типа «многие к одному», либо EntityCollection в элементе «много» связи типа «один ко многим» или «многие ко многим». Дополнительные сведения см. в разделе Связи в модели EDM.

Можно сформировать запрос Entity SQL или LINQ to Entities, который будет явно переходить по этим связям при помощи свойств навигации. Дополнительные сведения см. в разделе Как переходить по связям с помощью свойств навигации (платформа Entity Framework). Однако для формирования результатов запроса явное перемещение по связям не требуется. Существует два других способа распространить результаты запроса, чтобы загрузить также и объекты, на которые существуют ссылки: можно указать пути запросов или явно загрузить связанные объекты при помощи свойств навигации. Чтобы добиться еще большего контроля над результатами, можно указать путь запроса, а затем явно загрузить только выбранные связанные объекты.

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

Указание пути запроса для формирования результатов запроса

Чтобы указать путь запроса, передайте строковое представление графа объекта методу Include в запросе ObjectQuery. Этот путь указывает, какие связанные объекты должны быть возвращены при выполнении запроса объектов. Например, путь запроса, указанный в запросе для объектов Contact, гарантирует, что все связанные объекты SalesOrderHeader и SalesOrderDetail будут возвращены. Это показано в следующих запросах, в которых используется LINQ to Entities, Entity SQL, а также методы построителя запросов.

  • LINQ to Entities

    ' Define a LINQ query with a path that returns 
    ' orders and items for a contact.
    Dim contacts = (From contact In context.Contact _
        .Include("SalesOrderHeader.SalesOrderDetail") _
        Select contact).FirstOrDefault()
    
    // Define a LINQ query with a path that returns 
    // orders and items for a contact.
    var contacts = (from contact in context.Contact
                  .Include("SalesOrderHeader.SalesOrderDetail")
                  select contact).FirstOrDefault();
    
  • Entity SQL

    ' Define an object query with a path that returns 
    ' orders and items for a specific contact.              
    Dim queryString As String = _
        "SELECT VALUE TOP(1) Contact FROM " + _
        "AdventureWorksEntities.Contact AS Contact"
    
    ' Define the object query with the query string.
    Dim contactQuery As New ObjectQuery(Of Contact)(queryString, _
        context, MergeOption.NoTracking)
    
    Dim contact As Contact = _
    contactQuery.Include("SalesOrderHeader.SalesOrderDetail") _
        .FirstOrDefault()
    
    // Define an object query with a path that returns 
    // orders and items for a specific contact.              
    string queryString =
        @"SELECT VALUE TOP(1) Contact FROM " + 
        "AdventureWorksEntities.Contact AS Contact";
    
    // Define the object query with the query string.
    ObjectQuery<Contact> contactQuery = new ObjectQuery<Contact>(queryString, 
        context, MergeOption.NoTracking);
    
    Contact contact =
        contactQuery.Include("SalesOrderHeader.SalesOrderDetail")
        .FirstOrDefault();
    
  • Методы построителя запросов

    ' Create an object query with a path that returns orders and items for a contact.
    Dim contact As Contact = _
        context.Contact.Include("SalesOrderHeader.SalesOrderDetail") _
        .FirstOrDefault()
    
    // Define an object query with a path that returns 
    // orders and items for a specific contact.
    Contact contact =
        context.Contact.Include("SalesOrderHeader.SalesOrderDetail")
        .FirstOrDefault();
    

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

  • Пути запроса можно использовать с методами построителя запросов и запросами LINQ.

  • При вызове метода Include путь запроса действителен только для возвращаемого экземпляра ObjectQuery. Другие экземпляры запроса ObjectQuery и контекст объекта не затрагиваются.

  • Поскольку метод Include возвращает объект запроса, для объекта ObjectQuery этот метод можно вызывать многократно, чтобы включать объекты из нескольких связей, как в следующем примере:

    ' Create a SalesOrderHeader query with two query paths, 
    ' one that returns order items and a second that returns the 
    ' billing and shipping addresses for each order.
    Dim query As ObjectQuery(Of SalesOrderHeader) = _
        context.SalesOrderHeader.Include("SalesOrderDetail").Include("Address")
    
    // Create a SalesOrderHeader query with two query paths, 
    // one that returns order items and a second that returns the 
    // billing and shipping addresses for each order.
    ObjectQuery<SalesOrderHeader> query =
        context.SalesOrderHeader.Include("SalesOrderDetail").Include("Address");
    
  • Использование путей запроса может привести к тому, что над источником данных будут выполняться сложные команды из, на первый взгляд, простых запросов к объектам. Происходит это потому, что для возвращения связанных объектов в рамках одного запроса требуется одно или несколько соединений. Сложность будет выше в запросах к сложным моделям EDM, таким как, например, сущность с наследованием или путь, содержащий связи типа «многие ко многим». Используйте метод ToTraceString, чтобы увидеть команду, которая будет сформирована методом ObjectQuery. Дополнительные сведения см. в разделе Запросы объектов (платформа Entity Framework). Когда путь запроса содержит слишком много связанных объектов или эти объекты содержат слишком много строковых данных, источник данных может оказаться не в состоянии выполнить запрос. Это происходит, если запросу требуется промежуточное временное хранилище, которое превышает возможности источника данных. В этом случае можно снизить сложность запроса к источнику данных путем явной загрузки связанных объектов.

Дополнительные сведения см. в разделе Как использовать пути запросов для формирования результатов (платформа Entity Framework).

Явная загрузка связанных объектов

Чтобы загрузить связанные объекты явным образом, необходимо вызвать метод Load для связанного элемента, возвращенного свойством навигации. Для связи типа «один ко многим» вызовите метод Load для объекта EntityCollection, а для взаимно-однозначной связи — метод Load для объекта EntityReference. В результате данные связанного объекта будут загружены в контекст объекта. Если запрос возвращает коллекцию объектов, можно выполнить перечисление по коллекции и вызвать метод Load, чтобы загрузить связанные объекты для каждого объекта в коллекции, например каждый объект SalesOrderDetail, принадлежащий объекту SalesOrderHeader. В следующем примере объекты SalesOrderDetail загружаются явным образом для указанного объекта SalesOrderHeader:

' Load the items for the order if not already loaded.
If Not order.SalesOrderDetail.IsLoaded Then
    order.SalesOrderDetail.Load()
End If
// Load the items for the order if not already loaded.
if (!order.SalesOrderDetail.IsLoaded)
{
    order.SalesOrderDetail.Load();
}
NoteПримечание.

Если метод Load вызывается во время перечисления foreach (C#) или For Each (Visual Basic), службы объектов пытаются открыть новый модуль чтения данных. Эта операция завершится ошибкой, если не был включен режим MARS путем задания multipleactiveresultsets=true в строке соединения. Дополнительные сведения см. в разделе Использование режима MARS на веб-узле MSDN. Кроме того, результаты запроса можно загрузить в коллекцию List, при этом модуль чтения данных будет закрыт и можно будет перечислить коллекцию, чтобы загрузить объекты, на которые имеются ссылки.

Дополнительные сведения см. в разделе Как явно загружать связанные объекты (платформа Entity Framework).

Запрос связанных объектов

Поскольку класс EntityCollection реализует интерфейс IEnumerable, это позволяет использовать LINQ, чтобы запрашивать коллекцию объектов, загруженную в объект EntityCollection, возвращенный свойством навигации. Выполнение такого запроса возможно независимо от того, были ли объекты загружены в контекст объекта неявным образом путем указания пути запроса или загружены явным образом при помощи вызова метода Load.

Вызов метода CreateSourceQuery для объекта EntityCollection позволяет запрашивать связанные объекты без первоначальной загрузки объектов в коллекцию. Метод CreateSourceQuery возвращает объект ObjectQuery, который при своем выполнении возвращает тот же набор объектов, что и вызов метода Load. К этому запросу объектов можно применять методы построителя запросов, чтобы осуществлять дополнительную фильтрацию объектов, загруженных в коллекцию. Дополнительные сведения см. в разделе Как выполнять запросы к связанным объектам в коллекции EntityCollection (платформа Entity Framework).

Объект ObjectQuery возвращает данные модели EDM в форме объектов сущности. Однако когда в проекцию запроса включается свойство навигации, объект ObjectQuery возвращает вложенный объект DbDataRecord, содержащий связанные объекты. Дополнительные сведения см. в разделе Как переходить по связям с помощью свойств навигации (платформа Entity Framework).

См. также

Основные понятия

Запросы к данным как к объектам (платформа Entity Framework)
Запросы объектов (платформа Entity Framework)
Методы построителя запросов (платформа Entity Framework)