Loading Related Objects
This topic describes patterns that you can use to load related entities. Entity types can define navigation properties that represent associations in the data model. You can use these properties to load entities that are related to the returned entity by the defined association. When entities are generated based on the data model, navigation properties are generated for entities at both ends of an association. These navigation properties return either a reference on the "one" end of a one-to-one or many-to-one relationship or a collection on the "many" end of a one-to-many or many-to-many relationship. For more information, see Navigation Properties and Defining and Managing Relationships.
The following patterns describe the ways in which you can load related entities:
Specified in the query
You can compose an Entity SQL or LINQ to Entities query that explicitly navigates relationships by using navigation properties. When you execute such a query, the related entities that are included as navigation properties in the outmost projection of the query are returned. For more information, see
Explicitly loading entities into the ObjectContext 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 entities being loaded. Use the Load method on an EntityCollection or EntityReference or the LoadProperty method on the ObjectContext to explicitly retrieve the related entities from the data source. Each call to the Load method opens a connection to the database to retrieve the related information. This ensures that a query is never executed without an explicit request for the related entity. Explicit loading is the default behavior of the Entity Framework.
Before Load is called, a small amount of information about the related entity is already loaded into the ObjectContext.
For more information, see the Explicitly Loading Related Objects section of this topic.
In this type of loading, related entities are automatically loaded from the data source when you access a navigation property. With this type of loading, be aware that each navigation property that you access results in a separate query executing against the data source if the entity is not already in the ObjectContext.
For more information, see the Lazy Loading section of this topic.
Defining Query Paths with Include
When you know the exact shape of the graph of related entities that your application requires, you can use the Include method on the ObjectQuery to define a query path that controls which related entities to return as part of the initial query. When you define a query path, only a single request against the database is required to return all entities defined by the path in a single result set, and all related entities of the type specified in the path are loaded with each object that the query returns.
For more information, see the Defining a Query Path to Shape Query Results section of this topic.
Explicitly Loading Related Entity Objects
To explicitly load related entities, you must call the Load method on the related end returned 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 method on EntityReference. If you are working with POCO entities, use the LoadProperty method on the ObjectContext. For more information, see Loading Related POCO Entities. The LoadProperty method can be used with entities derived from EntityObject as well. These methods load 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.
When you call the Load method during a foreach (C#) or For Each (Visual Basic) enumeration, the Entity Framework 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 entities.
For more information, see How to: Explicitly Load Related Objects.
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 entities 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 query:
' Define a LINQ query with a path that returns ' orders and items for a contact. Dim contacts = (From contact In context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails") _ Select contact).FirstOrDefault()
// 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();
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 entities from multiple relationships, as in the following example:
' 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.SalesOrderHeaders.Include("SalesOrderDetails").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.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 entities 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. 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. If after optimizing a complex query you still get frequent timeouts, consider increasing the timeout value by setting the CommandTimeout property.
For more information, see How to: Use Query Paths to Shape Results.
Lazily Loading Entity Objects
The Entity Framework supports lazy loading of related entities. 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, LazyLoadingEnabled is set to true in the object context's constructor. With lazy loading enabled, related entities 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 together with eager loading. In this manner, a base data graph can be defined by using query paths, and additional related entities 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.
The following should be considered when you are using lazy loading:
Lazy loading is supported for navigation properties that return both a single entity (such as an EntityReference) and a collection of entities (such as an EntityCollection).
If lazy loading is enabled and a related entity is already loaded, it will not be loaded again.
Lazy loading is supported for entities 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 entity may including more data than anticipated.
Additional considerations apply when you use lazy loading with POCO entities. For more information, see Loading Related POCO Entities.
Querying Related Entity Objects
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.
An ObjectQuery returns entity data as entities. However when a navigation property is included in the outmost query projection, the query also returns the related entities accessed by the navigation. For more information, see How to: Navigate Relationships Using Navigation Properties.
When you choose a pattern for loading related entities, consider the behavior of each approach with regard to the number and timing of connections made to the data source versus the amount of data returned by and the complexity of using a single query. Eager loading returns all related entities together with the queried entities in a single query. This means that, while there is only one connection made to the data source, a larger amount of data is returned in the initial query. Also, query paths result in a more complex query because of the additional joins that are required in the query that is executed against the data source.
Explicit and lazy loading enables you to postpone the request for related object data until that data is actually needed. This yields a less complex initial query that returns less total data. However, each successive loading of a related object makes a connection to the data source and executes a query. In the case of lazy loading, this connection occurs whenever a navigation property is accessed and the related entity is not already loaded. If you are concerned about which related entities are returned by the initial query or with managing the timing of when related entities are loaded from the data source, you should consider disabling lazy loading. Lazy loading is enabled in the constructor of the Entity Framework-generated object context.
For more information, see Performance Considerations (Entity Framework).