Entity Framework:由重复访问数据库想到的...

    在上一文末写了几个关于用Include加载多级实体的查询,不过前天在forums.mircosoft.com看到一个关于Include加载多级实体的问题,经过一番交流和测试,算是明白了所以然.虽然自己常常在那样写Linq To Entity查询,也许是因为在使用的过程中没有遇到棘手的问题,所以也没去多想.

     在本文之前,还是先说说那个问题.在edm中这样的一个关系:Customers 1 --- * Orders * --- 1 Status,在这个关系下面做这样一个查询 var = query from customer in Customers.Include("Orders.Status") select customer,在调试的时候他发现Customer的Order被及时加载(PreLoad),Status却没有.所以问题人觉得这是不是EF在设计上的缘故,还是其他什么原因.我告诉他不是设计上的原因,因为我就常那么写,当然标准的写法是Inclue("Orders").Include("Orders.Status").之前我在adonot blog上看到关于Linq to Sql与 Linq to Entity 在Eager Loading方式上的区别,也见过那样写,当然最关键的,我那样做查询没有出先上述的问题.不过我还是在想,难道这个查询出现问题是和模型的1:n:1关系有关吗?以前都没在意这些,我在使用过类似这种查询的地方,的确没有符合这种关系.于是我昨天做了一个测试在Northwind里面恰好有Products 1--* OrderDetails *--1 Orders 符合条件的一组关系,并做了写了如下的代码,一边debug,一边跟踪数据库,的确只生成一条sql.后来我又选了1:n:n以及Customer 1:n Order 1:nOrderDetails的关系组也均都只生成一条sql.

Code
        接下来就入正题,什么是重复访问数据库,还是看下面的一段代码(使用Northwind数据库生成的edm),
Code

Entity Framework:由重复访问数据库想到的...             

         在上面这段代码中,通过getOrderListByCity方法London城市的Orders,并由每一个Order查找相应Customer的CustomerID.由于存在一个循环,故总共访问数据33次.但是真的是由于Orders.CustomerID有33个吗?显然不是,从上图运行结果来看就知道,其中有很多CustomerID是重复的.那有什么方法阻止数据库重复查询呢?.在EF内对于关连实体(导航属性)除了关联实体外还有一个属性**Reference属性,该属性暴露了一个属性IsLoad,判断关联实体是否已经加载.在EF中实体是依靠entityKey(数据库表主键)来识别的,一旦该entity Key对应的实体已被加载,context就不会重复去数据库去取了,如果该entity key对应实体没有被加载,就会去数据库去取.所以增加这样一个判断(红颜色的)

Code

Entity Framework:由重复访问数据库想到的...

      访问数据库的次数为5.原因是在EF中有一个对象跟踪服务(Object Track Service),在每一个对象加载到context都会对该对象进行跟踪并给予相应的状态(Detach,unchanged...),每一次在访问Order的每一个CustomerID时会先去自己的跟踪存储里面判断该对象是够存在.而IsLoad属性即是反馈对象跟踪的结果.好像Customer和Order是1:n的关系,Order访问CustomerReference属性.反过来似乎没有OrderReference属性,但是还是有customer.Orders.IsLoad属性可以判断的(在我之前的文章理由有介绍过的).

    上面的取得每一个Customer对象都是采用Lazy Loading的方式加载进来的,在Northwind数据库里取出ShipCity="London"查询了5次,那么使用Eager Loading会是怎样呢?只需将getOrderListByCity方法做一下修改,添加一个Include.可以猜到运行的结果是访问数据库次数为0,因为在取Order时已经取出了所有相关的Customer.

Code

   似乎这个小例子让我明白了在EF中Lazy Loading 与Eager Loading的本质区别,不过先还是看看采用这2种不同的方式,在数据库查询次数和表现上的不同:

     Lazy Loading总计访问了6次数据库(包括取Order),每一次执行的单表查询(第一次是对Order表查询 ,后5次对Customer表查询 ).

     Eager Loading只访问了一次数据库,但是join了2张表,连接Customer是必须的,为什么和join Order表本身(不理解,在Lazy Loading下第一次查询也join了Order本身) .

    在了解了这2种方式在sql查询上的不同,我觉得Lazy Laoding就如同是Eager Loading的可以控制的分步实现(有种化整为零的感觉,个人观点),也许这种策略对于大数据量的查询是一个很好的方式,当然前提是牺牲了数据库查询次数为代价的.我甚至不明白牺牲数据库访问次数相比一次join多张表是不是代价更低?也许问题该这么问,相比而言数据库访问次数和一次取大数据量那个在应用时更容易成为性能的瓶颈?

你可能感兴趣的:(framework)