1

I am having an odd problem with data loading which I don't understand, and I am hoping someone can explain to me what is going on, and perhaps how to accomplish my task more directly.

I am building a website using the technologies listed in the subject of this question.

I have a set of objects - each object has several properties (Name, ID, etc.) and a collection (ICollection<>) of other objects. So just looking at the tree of objects and their collections, it looks like this:

Tab
-TabRows
--Sections
---SectionRow
----Article

(So each tab has one or more tabrows, each tabrow has one or more sections, and so on. Each sub-object has a link back the parent, so each sectionrow has a SectionID, each Section has a TabRowID, etc.)

OK, so given that structure, consider this code:

// GET api/Tab/5
public Tab GetTab(int id)
{
    var tab = db.Tabs.FirstOrDefault(t => t.TabId == id);
    var tabrows = db.TabRows.ToList();
    var sections = db.Sections.ToList(); // This makes the tabRow.Sections populate
    var sectionrows = db.SectionRows.ToList();
    var articles = db.Articles.ToList();
    return tab;
}

So here is what happens. When the first line (var tab =...) executes, I get a tab object, but the TabRows collection is empty. (It is not null because the constructor instantiates it).

When the second line (var tabrows =...) executes, tab.TabRows suddenly populates. tab.TabRows.Sections is empty.

When the third line executes, tab.TabRows.Sections suddenly populates.

And so on.

I am assuming this is some sort of "lazy loading" on behalf of Linq, or perhaps one of the other technologies. But I don't know them well enough to figure it out.

Is there a way to re-write this so that I can just call line 1 and basically have everything auto-populate without having to individually reference every single object in every single collection?

Todd Davis
  • 5,855
  • 10
  • 53
  • 89
  • Please do not use the subject for the technologies, that is what the tags are for – Justin Pihony May 23 '13 at 04:03
  • possible duplicate of [Disable all lazy loading or force eager loading for a LINQ context](http://stackoverflow.com/questions/3388276/disable-all-lazy-loading-or-force-eager-loading-for-a-linq-context) – Preet Sangha May 23 '13 at 04:04
  • Can we get the code for your models? When you have navigation properties (properties of other models) you have to set to property to virtual to have lazy loading work correctly. Without that you have to use eager loading, with something like db.TabRows.Include(x => x.Sections).ToList() – DSlagle May 23 '13 at 04:07

1 Answers1

3

Lazy loading is enabled by default and eager loading disabled. Entity framework allows you to hint at eager loading using the include statements. Your statement will become something like this.

 var tab = db.Tabs.FirstOrDefault(t => t.TabId == id).Include("TabRows");

or as Include(t => t.TabRows);

Take a look at this link for more information.

In your case you would need to handle nested includes as well. Which means you would be better off taking another Model (your class) structured as follows

 Tabs -> Containing a List<TabRows> -> containing a List<Sections> etc. 

You would then need to re-write the linq so it populates the entire Model including the nested entities using nested includes.

As a side note, too many of these inner joins might slow down your querying and so consider indexed views on your DB side if and when possible

eightyeight
  • 498
  • 3
  • 6
  • 2
    It would actually be `db.Tabs.Include(t => t.TabRows).FirstOrDefault(t => t.TabId == id);`. `Include` is an extension to `DbQuery` – Ed S. May 23 '13 at 06:28