What effect(s) can the virtual keyword have in Entity Framework 4.1 POCO Code First?
Asked Answered
D

2

252

Does the virtual keyword has an effect when used on the properties in EF Code First?. Can someone describe all of its ramifications in different situations?

For instance, I know it can control lazy loading -- if you use the virtual keyword on an ICollection/one-to-many relationship property, it will be lazy-loaded by default, whereas if you leave the virtual keyword out, it will be eager-loaded.

What other effects can virtual keyword have in EF with POCO entities?. Should I make it default to use virtual on all my properties, or default to not using it?

Dulcinea answered 8/4, 2011 at 16:2 Comment(0)
D
205

So far, I know of these effects.

  • Lazy Loading: Any virtual ICollections will be lazy-loaded unless you specifically mark them otherwise.
  • More efficient change tracking. If you meet all the following requirements then your change tracking can use a more efficient method by hooking your virtual properties. From the link:

    To get change tracking proxies, the basic rule is that your class must be public, non-abstract or non-sealed. Your class must also implement public virtual getters/setters for all properties that are persisted. Finally, you must declare collection based relationship navigation properties as ICollection<T> only. They cannot be a concrete implementation or another interface that derives from ICollection<T> (a difference from the Deferred Loading proxy)

Another useful link describing this is MSDN's Requirements for Creating POCO Proxies.

Dulcinea answered 8/4, 2011 at 18:25 Comment(8)
There is no other reason to make properties virtual. Navigation properties are marked as virtual for lazy loading and scalar properties are marked as virtual for change tracking.Filose
what are navigation properties and what are scalar properties?Focalize
@AbidAli: I believe a navigation property is a foreign key (an entity class type) or a one to many relationship (of type ICollection<>). A scalar property is a base type (int, string, ..) or a ComplexType (which is just a struct of base types).Dulcinea
Is "public virtual byte[] bigData { get; set; }" lazy loading ?Welcher
bytes[] will be eagerly loaded, only foreign keys can be lazy. If you don't want to fetch that column, never fetch the whole record - just .Select(a=>new { fields you want }).Dulcinea
Is this really the best answer still?Educational
how to explicitly mark a virtual as not being lazy loaded?Olive
Both the links in the answer's dot points are broken/old. Here is a relevant MSDN result (found with googling the blog title; both find this same result): learn.microsoft.com/en-us/ef/ef6/querying/related-dataCourtyard
K
83

This virtual keyword is related to the topic of loading data from entity framework (lazy loading, eager loading and explicit loading).

You should use virtual keyword, when you want to load data with lazy loading.

lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time it is accessed.

For example, when using the Blog entity class defined below, the related Posts will be loaded the first time the Posts navigation property is accessed:

public class Blog 
{  
     public int BlogId { get; set; }  
     public string Name { get; set; }  
     public string Url { get; set; }  
     public string Tags { get; set; }  
     public virtual ICollection<Post> Posts { get; set; }  
}

Lazy loading of the Posts collection can be turned off by making the Posts property non-virtual.

if lazy loading is off, Loading of the Posts collection can still be achieved using eager loading (using Include method) or Explicitly loading related entities (using Load method).

Eagerly Loading:

using (var context = new BloggingContext()) 
{ 
    // Load all blogs and related posts 
    var blogs1 = context.Blogs 
                          .Include(b => b.Posts) 
                          .ToList(); 
}

Explicitly Loading:

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 

    // Load the posts related to a given blog 
    context.Entry(blog).Collection(p => p.Posts).Load(); 
}
Kauppi answered 6/1, 2016 at 20:6 Comment(2)
How to avoid N+1 problem when using virtual (lazy-loading)? For example, context.Blogs.ToList(); then it will not join tables, and it will run the select query as much as number of blogs.Finis
@Expertwannabe Even if you use lazy-loading, you still can explicitly request eager loading with a call to Include().Hypercatalectic

© 2022 - 2024 — McMap. All rights reserved.