1
votes

I have an album class and two classes linked to it, genre and artist. I use eager loading to load the album objects and the linked entities:

var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre);

After loading, I try to access the properties of the linked entities from an album object in the dataset, but the navigation properties are null

Album album = db.Albums.Find(id);
var name = album.Genre.Name;

name is null.

My question is, after the eager loading, do the objects loaded in the album dataset contain the references to the linked entities "artist" and "genre"?

I don't want to activate lazy loading.

Thanks

1
db.Albums.Find() executes a separate query. Use Album album = albums.FirstOrDefault(a => a.Id == id);. Then, you can access album.Genre. - 41686d6564
Is this the same instance of db? Once they are in the change tracker, they should be linked. - Jeremy Lakeman
@JeremyLakeman Only when the albums query is actually loaded into memory (which is not the case here). Calling albums.ToList() or albums.Load() should do the trick. - 41686d6564
Right.. missed that albums was still an IQueryable. - Jeremy Lakeman

1 Answers

0
votes

When Lazy Loading is enabled, the navigation property (linked entity or collection of entities) gets automatically loaded when you access it for the first time. That's why album.Genre would work fine as long as the DbContext is not yet disposed or if the Genre property (of a certain Album) has been accessed before.

When Lazy Loading is disabled, you don't have that flexibility. You need to eagerly (or explicitly) load the linked entities. You are off to the right start by using Include() (Eagerly Loading). However, since albums is not yet materialized (not loaded into memory), attempting to access the Genre property by executing a different query (which is what db.Albums.Find() does) will fail.

You have two options here...

Materialize the query:

var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre).ToList();
Album album = db.Albums.Find(id);
// Works because all `Album.Genre` **of all `Album` records** is loaded into the EF cache.
var name = album.Genre.Name;

Find the target Album using the same query that includes linked entities:

var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre)
// This will force EF to load the "included" entities for this one specific record.
Album album = albums.FirstOrDefault(a => a.Id == id);
var name = album.Genre.Name;