(LINQ to SQL):foreach调用GetEnumerator()方法所产生的疑惑

shichengboy 2008-02-25 11:41:41
刚接触LINQ,故而在学习过程中,产生了些许疑惑,希望能得到探讨....

大家知道,linq查询表达式,只是一种表达式的描述,真正执行查询的是通过foreach循环,来调用GetEnumerator()方法,执行linq查询表达式,所以这也就产生了LINQ的延迟执行问题,先看下面两个例子:

示例一:
IQueryable<Category> result = from c in db.Categorys
where c.Name.Length > 1
select c;

foreach (Category item in result)
{
Debug.WriteLine(item.Name);
}

Debug.WriteLine("-------------------");

foreach (Category item in result)
{
Debug.WriteLine(item.Name);
}
上代码中,是对单一表Categorys进行查询操作,取出其Name属性长度大于1的结果来,使用了两个foreach循环,在其两个foreach之间插入一个断点,运行后,程序被断在断点处,此时,已执行了第一个foreach循环,得出数据"FISH",然后直接修改数据库表,将"FISH"修改为"SMALLFISH",修改成功后,继续运行代码,如果每个foreach循环都调用一次GetEnumerator(),那么第二个foreach也会调用,也就是说对数据库执行第二次查询操作,所以第二个foreach执行结果应该为数据库表修改后的"SMALLFISH"才正确,可示例结果依然为"FISH",也就是说第二个foreach并未真正进行重新查询,而好像是从第一个foreach查询缓存中直接取出数据,所以才造成这个结果.

示例二:
IQueryable<Product> result =
(from c in db.Categorys
where c.CategoryId == "FISH"
from p in c.Products
select p);
foreach (Product item in result)
{
Debug.WriteLine(item.ProductId);
}

Debug.WriteLine("-----------------");

foreach (Product item in result)
{
Debug.WriteLine(item.ProductId);
}
示例二,同示例一类似,唯一不同的是,进行了多表操作,也就是将表Category 和 Product表通过"CategoryId"进行关联,查询出,Product中,CategoryId为"FISH"的产品信息出来.在运行代码时,和示例的操作完全相同,也在两个foreach间插入断点,在执行完第一个foreach后,直接修改数据库表,然后再接着执行第二个foreach操作,然后两次foreach出来的结果不同,换句话说,第二个foreach查询出来的是数据库表修改后的结果,也就是说第二个foreach还是重新调用了一次GetEnumerator()方法,所以取出的结果是修改后的结果.

问题:LINQ TO SQL 是通过foreach调用GetEnumerator()方法来执行LINQ查询表达式的,所以,按道理,示例中,不管操作一个表还是多个表,每个foreach均需要调用GetEnumerator()方法来执行查询,从而得出的结果应该是不同的,可现在出现的情况是,操作单一表,第二个foreach并未重新执行查询,操作多表时,第二个foreach才会重新执行查询,请问各位朋友,这个问题该如何来解释??小弟万谢~~~
...全文
851 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
yezie 2010-04-09
  • 打赏
  • 举报
回复
再次查询或使用result的时候
先db.Refresh(RefreshMode.KeepChanges, result);
SlaughtChen 2008-07-24
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 Ivony 的回复:]
你可以这样理解IQueryable接口,他是一个由查询定义的容器,当你第一次获取容器内容时,则他会自动执行查询来产生出内容,但不会每一次都去重新查询一次。

认为每一次获取其内容其都应该重新查询的理解应该是错的。
[/Quote]
顶一个,LINQ 就查询了一次.foreach 都用同一个实体. 可以这样理解吗
  • 打赏
  • 举报
回复
从非常"保险"的要求上来说(牺牲性能),不论查询是否非常简单,应用程序对数据根本不缓存是"最正确"的能够保证数据一致性的方法.但是我们真正的程序却反而需要大量使用缓存.既然缓存,就必然有这类问题.
  • 打赏
  • 举报
回复
并不都是“一个表达式翻译为一个SQL然后查询出所有结果”这么简单。实际上当处理复杂的表达式时,可能前半部分可以翻译为一个SQL,然后后半部分是运行时翻译为许多个(成千上万)个SQL,或者甚至可能后半部分根本不翻译为SQL二十是调用内存中的对象。
  • 打赏
  • 举报
回复
你的属性 Category.Products 如何定义的呢? IList?
Ivony 2008-02-27
  • 打赏
  • 举报
回复
介个正常,现在深入研究LINQ的人,两个手就能数出来。LINQ从第一天开始就非议不断,并不是每个人都看好它。LINQ的价值更多在于LINQ所带来的一些特性,如Lambda表达式。
shichengboy 2008-02-27
  • 打赏
  • 举报
回复
都这么些天了....也不见个相对更熟悉些的.....唉......
shichengboy 2008-02-27
  • 打赏
  • 举报
回复
恩 Lambda 确实挺新颖的,另外,扩展方法、匿名类型和表达式树 这三块也挺实用的。。。这些东东也都得多用,才能发现其中的优劣。。。。

另,挺看好XLINQ的,感觉将很不简单。。。。

继续学习ing。。。。
songsong13 2008-02-26
  • 打赏
  • 举报
回复
你说的我认同
shichengboy 2008-02-26
  • 打赏
  • 举报
回复
恩 同意你所说的 就是因为弄不清什么时候需要重新查询 什么时候只需从缓存里取结果 所以才疑惑。。。

等待比较熟悉的人吧。。。。。。。

貌似LINQ板块 对这新内容 感兴趣的人还是不太多啊

想把大乌龟给挖过来。。。就不知道他熟悉的怎样 嘿嘿
kbryant 2008-02-25
  • 打赏
  • 举报
回复
友情up
Ivony 2008-02-25
  • 打赏
  • 举报
回复
IQueryable定义上并没有说明自己会不会缓存查询结果,所以无论其缓存或是不缓存均是正常的。至于他以什么条件来决定这个查询结果是否失效需要重新查询,才是问题所在。

没研究过……
shichengboy 2008-02-25
  • 打赏
  • 举报
回复
To Ivony:
你的意思是说foreach调用的GetEnumerator()方法实际上是从第一次执行查询结果后的接口结果容器中取结果?

如果是这样的话,那在示例二中,同样的操作手法,仅不同的是LINQ表达式为两表关联,结果也应该与第一个foreach操作结果相同啊

可事实并非如此,示例二中第二个foreach并非从容器中取结果,得到的结果是断点处修改数据库后的数据,与第一个foreach并不同

起初我也是你这么想的,可后来我觉得并不是这么简单,应该还有其他的解释
Ivony 2008-02-25
  • 打赏
  • 举报
回复
你可以这样理解IQueryable接口,他是一个由查询定义的容器,当你第一次获取容器内容时,则他会自动执行查询来产生出内容,但不会每一次都去重新查询一次。

认为每一次获取其内容其都应该重新查询的理解应该是错的。
vwxyzh 2008-02-25
  • 打赏
  • 举报
回复
关注

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧