在EF Code First的属性上使用virtual关键字是否有影响?有人能描述一下它在不同情况下的所有后果吗?

例如,我知道它可以控制惰性加载——如果在ICollection/一对多关系属性上使用virtual关键字,默认情况下它将被惰性加载,而如果不使用virtual关键字,它将被快速加载。

在EF中使用POCO实体的虚拟关键字还可以有哪些其他影响?我应该让它默认使用虚拟的所有属性,或默认不使用它?


到目前为止,我知道这些影响。

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)

描述这一点的另一个有用链接是MSDN的创建POCO代理的要求。


这个virtual关键字与从实体框架加载数据的主题有关(惰性加载、即时加载和显式加载)。

当你想用惰性加载加载数据时,你应该使用virtual关键字。

延迟加载是在第一次访问一个实体或实体的集合时自动从数据库加载它的过程。

例如,当使用下面定义的Blog实体类时,相关的Posts将在Posts导航属性第一次被访问时被加载:

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; }  
}

可以通过将Posts属性设置为非虚拟属性来关闭Posts集合的延迟加载。

如果延迟加载关闭,Posts集合的加载仍然可以使用立即加载(使用Include方法)或显式加载相关实体(使用Load方法)来实现。

急切地加载:

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

显式地加载:

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(); 
}