31

I am having two object classes

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    // Navigation
    public ICollection<Product> Products { get; set; }
}

public class Product
{
    public Guid Id { get; set; }

    // Navigation
    public User User { get; set; }
    public Guid User_Id { get; set; }

    public string Name { get; set; }
}

When i load a user using dataContext, i get the list of Products being null (this is ok).

If i add "virtual" keyword to Products list,

public virtual ICollection<Product> Products { get; set; }

when i load the user, i get the Products list as well.

Why is this happening? I thought that "virtual" keyword is used for not loading the entities unless you explicit this (using an "Include" statement)

I think i got it all wrong

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Catalin
  • 11,503
  • 19
  • 74
  • 147

2 Answers2

67

This is wrong

"virtual" keyword is used for not loading the entities unless you explicit this (using an "Include" statement)

Lazy Loading means that entities will be automatically loaded when you first access collection or navigation property, and that will happen transparently, as though they were always loaded with parent object.

Using "include" is loading on demand, when you specify properties you want to query.

Existence of virtual keyword is related only to lazy loading. virtual keyword allows entity framework runtime create dynamic proxies for your entity classes and their properties, and by that support lazy loading. Without virtual, lazy loading will not be supported, and you get null on collection properties.

Fact is that you can use "include" in any case, but without lazy loading it is the only way to access collection and navigation properties.

archil
  • 39,013
  • 7
  • 65
  • 82
  • _"Lazy Loading means that entities will be automatically loaded when you first access collection"_ This means that if i will never access user.Products property, the products will not be loaded, that's right? – Catalin Jul 13 '12 at 11:35
  • 5
    @RaraituL yes, that is right. When debugging, you actually **access** properties, and they get loaded if lazy loading is supported. So you could use sql profiler or tools like it to debug actual queries sent to database. – archil Jul 13 '12 at 11:47
  • @archil: If I don't write virtual with collection and use include then it's also loading something when only needed right? like lazy loading? so what's the difference? – azure boy Jan 21 '19 at 09:33
4

I guess you're quiring for a property which is a subject for lazy load while being into the ef context:

using (var db = new Context())
{
    var user = db.Users.Where(...);

    var products = user.Products; // being loaded right away
}

Try to leave it:

User user;
using (var db = new Context())
{
    user = db.Users.Where(...);

    // I guess you will need here:
    // .Include(u => u.Products)
}
var products = user.Products; // what error will you get here?
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • without using "virtual": User user = db.Users.First(); in debug mode, user.Products is null. using "virtual" keyword: User user = db.Users.First(); in debug mode, user.Products is a list of Products – Catalin Jul 13 '12 at 11:33
  • @RaraituL: As archil has already mentioned, you must use virtual keyword in Code First approach to make lazy loading possible. Then you can turn it on or off. – abatishchev Jul 13 '12 at 11:45
  • But the context was "closed" before "user.Products" so how the Lazy loading will work if there is context? – Nerf Apr 21 '17 at 13:49