Explicit Loading in EF Core is a technique we query and load the related entities with an explicit call. Explicit loading works very similar to Lazy Loading, but the loading of the related entities happens only after an explicit call to the Load or Query method of the related entity’s object. In eager loading, we query the related entities along with the main entity in a single Query. In Lazy loading, EF loads the load related entities whenever we access the related Property.DbContext.Entry(...) API
Database:
The Database for this tutorial is taken from the chinook database.Source Code:
The source code of this project available in GitHub. It also contains the script of the database
Table of Contents
Explicit Loading in Entity Framework Core
To make an explicit call to load a related entity, we use the Load method of the related entity’s DbContext.Entry(...)object.
To Invoke load method, first we use the DbContext.Entry method is used to gain access to a tracked entity. From the Entry, we can use the Reference or Collection method to get the reference to the navigational property. Then you can call the Load method to get the data from the database.
In the following example query, we retrieve five Tracks from the database. Inside the for loop, we first get the DbContext.Entry of the Track entity db.Entry(track)
Now, we can get the reference to the Album using the reference method.db.Entry(track).Reference(t => t.Album)
Finally, use the Load method (db.Entry(track).Reference(t => t.Album).Load();) to send the query to the database and load the related Album data.
Now, since the album is loaded, we can access its Entry method (db.Entry(track.Album)) and use it load the Artist entity. (db.Entry(track.Album).Reference(t => t.Artist).Load();)
1 2 3 4 5 6 7 8 9 10 11 12 13 | using (ChinookContext db = new ChinookContext()) { var Tracks = db.Track.Take(5).ToList(); foreach (var track in Tracks) { db.Entry(track).Reference(t => t.Album).Load(); db.Entry(track.Album).Reference(t => t.Artist).Load(); Console.WriteLine("{0} {1} {2}", track.Album.Title, track.Name, track.Album.Artist.Name); } } |
The corresponding SQL
1 2 3 4 5 6 7 8 9 10 11 12 | SELECT TOP(@__p_0) [t].[TrackId], [t].[AlbumId], [t].[Bytes], [t].[Composer], [t].[GenreId], [t].[MediaTypeId], [t].[Milliseconds], [t].[Name], [t].[UnitPrice] FROM [Track] AS [t] SELECT [a].[AlbumId], [a].[ArtistId], [a].[Title] FROM [Album] AS [a] WHERE [a].[AlbumId] = @__p_0 SELECT [a].[ArtistId], [a].[Name] FROM [Artist] AS [a] WHERE [a].[ArtistId] = @__p_0 |
Loading Collections
We use the reference method if the navigation property is of reference type. In the case of collection navigation property, the collection method is to be used
The Trackis a collection navigation property the entity Album. The following example retrieves the Albumand then uses the load method to explicitly load the that belong that album. Since it is a collection navigation property we make use of the TracksCollection method
1 2 3 | db.Entry(album).Collection(t => t.Track).Load(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using (ChinookContext db = new ChinookContext()) { var Albums = db.Album.Take(5).ToList(); foreach (var album in Albums) { db.Entry(album).Collection(t => t.Track).Load(); db.Entry(album).Reference(t => t.Artist).Load(); Console.WriteLine("{0} {1}", album.Title, album.Artist.Name); foreach (var track in album.Track) { Console.WriteLine("\t\t\t{0}", track.Name); } } } |
The SQL Query
1 2 3 4 5 6 7 8 9 10 11 12 | SELECT TOP(@__p_0) [a].[AlbumId], [a].[ArtistId], [a].[Title] FROM [Album] AS [a] SELECT [t].[TrackId], [t].[AlbumId], [t].[Bytes], [t].[Composer], [t].[GenreId], [t].[MediaTypeId], [t].[Milliseconds], [t].[Name], [t].[UnitPrice] FROM [Track] AS [t] WHERE [t].[AlbumId] = @__p_0 SELECT [a].[ArtistId], [a].[Name] FROM [Artist] AS [a] WHERE [a].[ArtistId] = @__p_0 |
Explicit Loading with Filtering
Unfortunately you cannot use the filter while using the Load method. For Example the following query results in an error.
1 2 3 | db.Entry(album).Collection(t => t.Track.Where(f => f.Name.StartsWith("A"))).Load(); |
To filter out the result of explicit loading, you can use the Query method. The query method returns the instance of IQueryable (or Query Variable). Hence you need to call Load() (or ToList(), FirstOrDefault() etc) to execute the query.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | using (ChinookContext db = new ChinookContext()) { var Albums = db.Album.Take(5).ToList(); foreach (var album in Albums) { db.Entry(album).Collection(t => t.Track).Query().Where(f => f.Name.Contains("The")).Load(); db.Entry(album).Reference(t => t.Artist).Query().Load(); //Also works //db.Entry(album).Collection(t => t.Track).Query().Where(f => f.Name.Contains("The")).ToList(); //db.Entry(album).Reference(t => t.Artist).Query().ToList(); Console.WriteLine("{0} {1}", album.Title, album.Artist.Name); foreach (var track in album.Track) { Console.WriteLine("\t\t\t{0}", track.Name); } } } |
Virtual Property
You do not have the navigation properties as virtual.for the explicit loading to work.
References
- CollectionEntry.Load Method
- CollectionEntry.Query Method
- NavigationEntry.Load Method
- NavigationEntry.Query Method
Summary
Explicit Loading uses the Load or Query method of the to load related data. Here you have full control over how & when the query is sent to the database. You can also filter the query using DbContext.Entry(...) APIwhere before sending it to the database using the Query method.

I have a solution I am converting from .NET Core 2.2 to 3.1. I have upgraded my Entity Framework packages. However, when trying to use .Collection() or .Reference() after loading the entry, I can only pass a string to these methods. An overload to pass in a lambda is not available. Is there an extension package I need to add to my project to get the lambda versions of .Collection() and .Reference()?
This is the code I am using that builds:
var item = _dbContext.Users.First();
var entry = _dbContext.Entry(item).Collection(“Address”);
What I am trying to use but get an error in VS Code that it cannot convert a lambda expression to a string:
var item = _dbContext.Users.First();
var entry = _dbContext.Entry(item).Collection(x => x.Address);
Check if you also updated correctly to EF Core & EF Core SQL server to 3.1.3.
No Need for any extension package