0%

鱼和熊掌不能兼得

——中国谚语

一、介绍#

 Entity Framework作为一个优秀的ORM框架,它使得操作数据库就像操作内存中的数据一样,但是这种抽象是有性能代价的,故鱼和熊掌不能兼得。但是,通过对EF的学习,可以避免不必要的性能损失。本篇只介绍关联实体的加载的相关知识,这在我之前的文章中都有介绍。

我们已经了解到EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,_Explicit Loading_,其中_Lazy Loading_和_Explicit Loading_都是延迟加载。

(一)Lazy Loading_使用的是动态代理,默认情况下,如果POCO类满足以下两个条件,EF就使用_Lazy Loading:

  1. POCO类是Public且不为Sealed。
  2. 导航属性标记为Virtual。

关闭Lazy Loading,可以将_LazyLoadingEnabled_设为false,如果导航属性没有标记为virtual,_Lazy Loading_也是不起作用的。

(二)_Eager Loading_使用Include方法关联预先加载的实体。

(三)_Explicit Loading_使用Entry方法,对于集合使用Collection,单个实体则使用Reference。

二、实例#

下面通过实例来理解这几种加载方式。

有下面三个实体:Province,City,Governor,一个Province有多个City,并且只有一个Governor。

1: public class Province

2: {

3: public int Id { get; set; }

4: public string Name { get; set; }

5:  

6: public virtual Governor Governor { get; set; }

7:  

8: public virtual List Cities { get; set; }

9: }

10:  

11: public class City

12: {

13: public int Id { get; set; }

14: public string Name { get; set; }

15: }

16:  

17:  

18: public class Governor

19: {

20: public int Id { get; set; }

21: public string Name { get; set; }

22: }

Lazy Loading

1: private static void LazyLoading(EFLoadingContext ctx)

2: {

3: //发送一条查询到数据库,查询所有的province

4: var list = ctx.Provines.ToList();

5: foreach (var province in list)

6: {

7: //每次遍历(用到导航属性时)都发送2条查询,一条查询当前province包含的city和另一条查询当前province的governor

8: //如果ctx.Configuration.LazyLoadingEnabled为false或者前者为true,但是导航属性没有标注为virtual,下面的操作都会抛出异常

9: Print(province);

10: }

11: }

Eager Loading

1: private static void EagerLoading(EFLoadingContext ctx)

2: {

3: //发送一条查询到数据库库,查询所有的province并关联city和governor

4: var list = ctx.Provines.Include(t => t.Cities).Include(t => t.Governor);

5: foreach (var province in list)

6: {

7: //不管ctx.Configuration.LazyLoadingEnabled为false,还是没有标注导航属性virtual,都不会抛出异常

8: Print(province);

9: }

10: }

Explicti Loading

1: private static void ExplicitLoading(EFLoadingContext ctx)

2: {

3: //发送一条查询到数据库,查询所有的province

4: var list = ctx.Provines.ToList();

5: foreach (var province in list)

6: {

7: var p = ctx.Entry(province);

8: //发送一条查询,查询所有当前province的city

9: p.Collection(t => t.Cities).Load();

10: //发送一条查询,查询当前province的governor

11: p.Reference(t => t.Governor).Load();

12: //不管ctx.Configuration.LazyLoadingEnabled为false,还是没有标注导航属性virtual,都不会抛出异常

13: Print(province);

14: }

15: }

Print方法

1: private static void Print(Province province)

2: {

3: Console.WriteLine(“省:【{0}】,市:【{1}】,省长:【{2}】”, province.Name, string.Join(“,”, province.Cities.Select(t => t.Name)), province.Governor.Name);

4: }

三、总结#

关于关联加载实体基本上就是这些内容吧,如果想看这部分详细的介绍,可以参考我这篇文章的后半部分。总的来说,这部分比较简单,一个LazyLoadingEnabled设置,三种加载方式。Lazy Loading会生成大量的sql,Eager Loading生成的关联查询比较负责,Explicit Loading同Lazy Loading一样生成很多的sql,但是有一些其他优点,比如:导航属性可以不用标注为virtual。如果这几种关联都不能解决实际问题,可以直接使用sql查询。

最后附上本文的demo,下载地址:http://pan.baidu.com/s/1i3IAiNF