Shaping Query Results (Entity Framework)
[This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.]

When you execute a query, only objects that are specifically requested in the query are returned. For example, when a query against the Adventure Works Sales Model returns Customer objects, by default the related SalesOrderHeader objects are not returned, even though there is a relationship between Customer and SalesOrderHeader. This behavior ensures that the application is always aware of the scope of the data that is returned from an object query. By default, the relationship objects that represent associations between entity types are always returned. When objects are generated based on the data model, navigation properties are generated for entity objects at both ends of an association. These navigation properties return either an EntityReference on the "one" end of a one-to-one or many-to-one relationship or an EntityCollection on the "many" end of a one-to-many or many-to-many relationship. For more information, see Entity Data Model Relationships.

You can compose an Entity SQL or LINQ to Entities query that explicitly navigates these relationships by using navigation properties. For more information, see How to: Navigate Relationships Using Navigation Properties (Entity Framework). However, you do not need to navigate relationships explicitly in your query to shape query results. There are other ways to extend the results of a query to also load referenced objects: you can specify query paths, or you can explicitly load related objects using navigation properties. To exercise additional control over the results, you can enumerate through the collection of objects that is returned by the query by using a foreach loop (For Each...Next in Visual Basic) and conditionally call the Load method on the EntityReference and EntityCollection properties for each entity in the results.

When considering which option to use, be aware that there is a tradeoff between the number of requests against the database and the amount of data returned in a single query. Query paths define the graph of objects returned by a query. When you define a query path, only a single request against the database is required to return all objects defined by the path in a single result set. Explicitly loading objects requires multiple round-trips to the database and might require multiple active result sets, but the amount of data returned is limited to only the objects being loaded.

If you are concerned about which related objects are returned by the initial query or with managing the timing of when related objects are loaded from the data source, you should consider disabling lazy loading. Lazy loading is enabled by default.

NoteNote

Slightly different loading patterns are needed when you use persistence-ignorant custom data classes. For more information, see Loading Related Persistence-Ignorant Objects (Entity Framework).

Defining a Query Path to Shape Query Results

To specify the query path, pass a string representation of the object graph to the Include method on the ObjectQuery. This path specifies which related objects to return when an object query is executed. For example, a query path defined on a query for Contact objects ensures that each related SalesOrderHeader and SalesOrderDetail will be returned. This is shown in the following queries that use LINQ to Entities, Entity SQL, and query builder methods.

LINQ to Entities
C#
// Define a LINQ query with a path that returns 
// orders and items for a contact.
var contacts = (from contact in context.Contacts
              .Include("SalesOrderHeaders.SalesOrderDetails")
                select contact).FirstOrDefault();
Entity SQL
C#
// 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.Contacts AS contact";

// Define the object query with the query string.
ObjectQuery<Contact> contactQuery = new ObjectQuery<Contact>(queryString,
    context, MergeOption.NoTracking);

Contact contact =
    contactQuery.Include("SalesOrderHeaders.SalesOrderDetails")
    .FirstOrDefault();
Query builder methods
C#
// Define an object query with a path that returns 
// orders and items for a specific contact.
Contact contact =
    context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails")
    .FirstOrDefault();

The following considerations apply when defining query paths:

  • Query paths can be used with query builder methods and LINQ queries.

  • When you call Include, the query path is only valid on the returned instance of ObjectQuery. Other instances of ObjectQuery and the object context itself are not affected.

  • Because Include returns the query object, you can call this method multiple times on an ObjectQuery to include objects from multiple relationships, as in the following example:

    C#
    // 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.SalesOrderHeaders.Include("SalesOrderDetails").Include("Address");
  • Using query paths can result in complex commands being executed against the data source from seemingly simple object queries. This occurs because one or more joins are required to return related objects in a single query, which results in redundant data for each related object being returned from the data source. This complexity is greater in queries against a complex model, such as an entity with inheritance or a path that includes many-to-many relationships. Use the ToTraceString method to see the command that will be generated by an ObjectQuery. For more information, see Object Queries (Entity Framework). When a query path includes too many related objects or the objects contain too much row data, the data source might not be able to complete the query. This occurs if the query requires intermediate temporary storage that exceeds the capabilities of the data source. When this occurs, you can reduce the complexity of the data source query by explicitly loading related objects or enabling deferred loading.

For more information, see How to: Use Query Paths to Shape Results (Entity Framework).

Explicitly Loading Related Objects

To explicitly load related objects, you must call the Load method on the related end retuned by the navigation property. For a one-to-many relationship, call the Load method on EntityCollection, and for a one-to-one relationship, call the Load on EntityReference. This loads the related object data into the object context. When a query returns results, you can enumerate through the collection of objects using a foreach loop (For Each...Next in Visual Basic) and conditionally call the Load method on the EntityReference and EntityCollection properties for each entity in the results.

NoteNote

When you call the Load method during a foreach (C#) or For Each (Visual Basic) enumeration, Object Services tries to open a new data reader. This operation will fail unless you have enabled multiple active results sets by specifying multipleactiveresultsets=true in the connection string. For more information, see Using Multiple Active Result Sets (MARS) on MSDN. You can also load the result of the query into a List collection, which closes the data reader and enables you to enumerate over the collection to load referenced objects.

For more information, see How to: Explicitly Load Related Objects (Entity Framework).

Lazy Loading

The Entity Framework supports lazy loading of related objects. In the Entity Framework runtime, the default value of the LazyLoadingEnabled property in an instance of an ObjectContext is false. However, if you use the Entity Framework tools to create a new model and the corresponding generated classes, the default for LazyLoadingEnabled is true. With lazy loading enabled, related objects are not loaded from the data source until they are accessed programmatically by the get accessor of a navigation property. To disable lazy loading, set the LazyLoadingEnabled property to false on the instance of ObjectContextOptions that is returned by the System.Data.Objects.ObjectContext.ContextOptions property.

Lazy loading can be used with eager loading. In this manner, a base data graph can be defined by using query paths, and additional related objects not included in the original query paths can be loaded as needed. For more information, see How to: Use Lazy Loading to Load Related Objects (Entity Framework).

The following should be considered when you are using lazy loading:

  • Lazy loading is supported for navigation properties that return both a single object (such as an EntityReference) and a collection of objects (such as an EntityCollection).

  • If lazy loading is enabled and a related object is already loaded, it will not be loaded again.

  • Lazy loading is supported for objects in a Detached state. In this case, related objects are also returned in a Detached state.

  • Lazy loading behavior is determined by the ObjectContext instance that is used to retrieve the object from the data source (even if the entity was loaded with the NoTracking MergeOption) or to which the object was added or attached. Because of this, the lazy loading behavior cannot be changed once this context has been disposed, and any further lazy loading operations will fail.

  • When serializing entities, consider disabling lazy loading. Otherwise, lazy loading will be triggered and the serialized objects may including more data than anticipated.

  • Additional considerations apply when you use lazy loading with persistence-ignorant objects. For more information, see Loading Related Persistence-Ignorant Objects (Entity Framework).

Querying Related Objects

Because the EntityCollection class implements the IEnumerable interface, you can use LINQ to query the collection of objects loaded into the EntityCollection returned by a navigation property. This works whether the objects are implicitly loaded into the object context by specifying a query path or explicitly loaded by calling the Load method.

Calling the CreateSourceQuery method on an EntityCollection enables you to query related objects without first loading objects into the collection. CreateSourceQuery returns an ObjectQuery that, when executed, returns the same set of objects as calling the Load method. Query builder methods can be applied to this object query to further filter objects loaded into the collection. For more information, see How to: Query Related Objects in an EntityCollection (Entity Framework).

An ObjectQuery returns entity data as entity objects. However when a navigation property is included in the outmost query projection, the query also returns the related objects accessed by the navigation. For more information, see How to: Navigate Relationships Using Navigation Properties (Entity Framework).

See Also

Page view tracker