2

I am trying to get my head around lazy loading in an ASP.Net MVC app. For instance, I have a class with a property that is a collection (Employees). I want the collection to only load when I need it loaded:

public class Department
{
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }

    [ForeignKey("DepartmentId")]
    public Lazy<ICollection<Employee>> Employees { get; set; }
}

First, I am not sure if I should lazy load the class or the collection

    public Lazy<ICollection<Employee>> Employees { get; set; }
    public ICollection<Lazy<Employee>> Employees { get; set; }

I assume the collection.

Next, I cannot seem to find a related example to actually load the property/collection once I need it and after the class has been instantiated. I am also not sure if this is done in the class itself or in my MVC controller.

Any help is appreciated.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
steveareeno
  • 1,925
  • 5
  • 39
  • 59
  • There are a *lot* of examples - when you *create* a new Lazy, you pass ghe factory method in its constructor. The factory will be called only when the Lazy's value is requested. Just declaring a `Lazy` property doesn't mean that anything will be evaluated lazily. – Panagiotis Kanavos Nov 02 '15 at 13:42
  • Is the Department class part of an EF model? In this case you don't need to declare the collection lazy – user449689 Nov 02 '15 at 13:43
  • BTW did you mix up lazy loading (an ORM concept) with the unrelated concept of lazy evaluation (what `Lazy` is about)? *Relation* are lazily loaded by default - you *have* to use the `Include()` call to eagerly load related objects. – Panagiotis Kanavos Nov 02 '15 at 13:44
  • it is EF code-first. There are a lot of examples but I am probably unable to decipher them and apply them to my example. – steveareeno Nov 02 '15 at 13:46
  • 1
    It's possible I am mixing up concepts. Basically, if I set the employee collection as a virtual, I will get all the employees for each dept. when I call the class. That is only a good idea when I want to show all employees for one depart. On the other hand, when I have a dept dropdown on an employee view I don't want to load every employee for every depart when I instantiate this class. Hope that makes sense. – steveareeno Nov 02 '15 at 13:50

2 Answers2

1

For lazy loading you must:

  • public virtual ICollection<Lazy<Employee>> Employees { get; set; }. You actually miss the virtual that allows the framework to create the proxy by overwritting the property;
  • context.Configuration.ProxyCreationEnabled = true;, this is the defautl value.
tschmit007
  • 7,559
  • 2
  • 35
  • 43
  • Actually, when I reread this post I think I might understand what is happening: http://stackoverflow.com/questions/11469432/entity-framework-code-first-lazy-loading When I had the property originally set as a virtual property (instead of Lazy) and was debugging, I was actually accessing the property, thereby loading it. That threw me for a loop. So if I just set it back to "public virtual ICollection Employees { get; set; } it should only load when the collection is accessed, right? – steveareeno Nov 02 '15 at 14:03
1

You don't have to use the Lazy<T> on your Employees property. You'll just be adding unnecessary "lazyness", since Entity Framework (and other ORMs like NHibernate) queries are already lazy, i.e.: the query will only hit the database when you explicitly tell it to.

So, by making Employees of type:

public virtual ICollection<Employee> Employees { get; set; } //make sure to mark it as virtual, otherwise it won't be lazy

When querying:

var result = myContextObj.Departments.Include(d=> d.Employees).Where(d=> d.Id == someID).SelectMany(d=> d.Employees);

The code above does nothing but create a Query Object representing the query that may be sent to the database.But it's not going to do anything, unless you "materialize" the result, either by doing a foreach on result, or calling ToList() for example.

Breno Ferreira
  • 1,196
  • 9
  • 8