AudioGuy AudioGuy - 1 year ago 96
C# Question

EF6: Setting DataGridView's DataSource to an EF-Entity results in loading its children as well. Why?

I am trying to keep this as short as possible:

I have a simple database with some tables:
artists, albums, songs.

  1. artists may have multiple albums. albums may have been created by multiple artists (many-to-many).

  2. albums may have multiple songs but one song is limited to one album (1-to-many).

The EntityFramework puts these tables into classes just fine. Now I'm binding my DbContext instance to a DataGridView in a Windows Forms C# project:

DBEntities db = new DBEntities();
db.Artists.Include(a => a.Albums).Load(); // include children albums as well
artistBindingSource.DataSource = db.Artists.Local.ToBindingList();

The DataGridView instance displays the content correctly. I can save changes and the like.

If the user clicks on a cell (with an artist's name) in the DataGridView, I am loading the related albums by assigning the second DataGridView (with albumBindingSource) to the artist's albums collection:

Artist a = (Artist)row.DataBoundItem; // row contains selected grid row
if (a != null)
albumBindingSource.DataSource = a.Albums;

This also works ok, but when debugging the SQL statements I found something peculiar:
When assigning the second DataGridView's DataSource to a.albums (that is the selected instance's albums), Entity Framework also lazy loads the album's songs in multiple SELECT statements (one for each song).

Question 1: Why is it loading the albums' children as well? I never told it to do so.

However: if I add the following code to the line where the entities are preloaded, the lazy loading disappears:

db.Artists.Include(c => c.Albums.Select(b => b.Songs)).Load();

Question 2: Do I really need to preload ALL children and grandchildren in order to prevent the lazy loading? I never wanted the grandchildren to appear in my Windows Form.

Question 3: (see Q.2) Why is it "include" and then "select"? I think something like...

db.Artists.Include(c => c.Albums.Include(d => d.Songs)).Load();

...would be way more intuitive.

Anyway: thanks for helping me out here!

Answer Source

It is loading entities probably because LazyLoading is turned on. You can turn of LazyLoading by db.Configuration.LazyLoadingEnabled = false; no need to load everything. Aditionally, there is two Include methods (not counting overloads). One is method of DbQuery<TEntity> and DbSet<TEntity> inherits it, so you can see Include method for your sets, another is in QuerableExtensions class, which is extension method of IQuerable<T>, which in the System.Data.Entity namespace. So it is written for IQuerable and you specify collection childrens using Select method.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download