虚拟关键字在Entity Framework 4.1 POCO Code First中会产生什么影响?

251

virtual关键字在EF Code First中的属性上使用时有影响吗?能否描述不同情况下它的全部影响?

例如,我知道它可以控制延迟加载 - 如果在ICollection/一对多关系属性上使用虚拟关键字,则默认情况下将进行延迟加载,而如果省略虚拟关键字,则将进行急切加载。

virtual关键字在EF中与POCO实体有哪些其他影响?我应该默认使用virtual在所有属性上,还是默认不使用它?

2个回答

204

到目前为止,我所知道的这些影响如下。

  • 延迟加载:除非你特别标记,否则任何 virtual ICollections 都会被延迟加载。
  • 更高效的更改跟踪。如果您满足以下所有要求,则更改跟踪可以通过挂接虚拟属性来使用更有效的方法。来自链接:

    要获得更改跟踪代理,基本规则是您的类必须是公共的、非抽象或非密封的。您的类还必须为持久化的所有属性实现公共虚拟 getter/setter。最后,您必须将基于集合的关系导航属性声明为仅限 ICollection<T>。它们不能是具体实现或从 ICollection<T> 派生的另一个接口(与Deferred Loading代理的不同)。

另一个有用的链接是 MSDN 的 创建 POCO 代理的要求


54
将属性设置为虚拟属性没有其他原因。导航属性被标记为虚拟以实现延迟加载,标量属性则被标记为虚拟以进行更改跟踪。 - Ladislav Mrnka
10
什么是导航属性和标量属性? 导航属性指的是实体类型之间的关系,可以用来导航到相关联的实体。例如,一个订单实体可能具有一个指向顾客实体的导航属性,以便在需要时可以轻松访问顾客数据。标量属性指的是实体类型中包含的普通属性,其值为单个标量(如字符串、数字或日期)。例如,订单实体可能具有包含订单号或订单日期等信息的标量属性。 - Abid Ali
9
@AbidAli:我认为导航属性是一个外键(实体类类型)或一对多关系(ICollection<>类型)。标量属性是基本类型(int、string等)或复杂类型(仅由基本类型构成的结构体)。 - Scott Stafford
2
"public virtual byte[] bigData { get; set; }" 是延迟加载吗? - AechoLiu
9
只有外键可以延迟加载,bytes[]将被急切地加载。如果您不想获取该列,请勿获取整个记录 - 只需使用.Select(a=>new { fields you want })选择您需要的字段。 - Scott Stafford
显示剩余3条评论

83

这个虚拟关键字与从实体框架(延迟加载、急切加载和显式加载)中加载数据的主题有关。

当你想使用延迟加载方式加载数据时,应该使用virtual关键字。

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

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


```C# public class Blog { public int BlogId { get; set; } public string Url { get; set; } public virtual ICollection Posts { get; set; } } ```
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属性非虚拟,可以关闭对文章集合的惰性加载。

如果关闭了惰性加载,则可以使用急切加载(使用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(); 
}

2
如何在使用虚拟(延迟加载)时避免N+1问题?例如,context.Blogs.ToList(); 它不会连接表,并且将运行与博客数量相同的选择查询。 - Expert wanna be
3
即使您使用了懒加载,仍然可以通过调用 Include() 来显式请求急切加载。 - Monsignor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接