Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在列表中使用.Where()_C#_Asp.net Mvc_Linq_Entity Framework_Linq To Entities - Fatal编程技术网

C# 在列表中使用.Where()

C# 在列表中使用.Where(),c#,asp.net-mvc,linq,entity-framework,linq-to-entities,C#,Asp.net Mvc,Linq,Entity Framework,Linq To Entities,假设一个视图中有以下两个可能的代码块,并使用类似returnview(db.Products.Find(id))的方式将模型传递给它 List reviews=Model.UserReviews.OrderByDescending(ur=>ur.Date.ToList(); 如果(myUserReview!=null) reviews=reviews.Where(ur=>ur.Id!=myUserReview.Id).ToList(); IEnumerable reviews=Model.U

假设一个视图中有以下两个可能的代码块,并使用类似
returnview(db.Products.Find(id))的方式将模型传递给它

List reviews=Model.UserReviews.OrderByDescending(ur=>ur.Date.ToList();
如果(myUserReview!=null)
reviews=reviews.Where(ur=>ur.Id!=myUserReview.Id).ToList();

IEnumerable reviews=Model.UserReviews.OrderByDescending(ur=>ur.Date);
如果(myUserReview!=null)
reviews=reviews.Where(ur=>ur.Id!=myUserReview.Id);

两者之间的性能影响是什么?至此,是否所有与产品相关的数据都在内存中,包括其导航属性?在这种情况下使用
ToList()
有什么关系吗?如果没有,是否有更好的方法在
列表上使用Linq查询而不必每次调用
ToList()
,或者这是一种典型的方法?

没有足够的上下文来确定

但是
ToList()
保证数据已经复制到内存中,您的第一个示例会执行两次

第二个示例可能涉及可查询的数据或其他一些按需场景。即使原始数据已全部存储在内存中,即使最后只添加了对
ToList()
的调用,也会比第一个示例少一个内存副本

在第二个例子中,当你看到这个小片段的结尾时,完全有可能没有对原始数据进行任何实际的处理。在这种情况下,在某些代码实际枚举最后的
reviews
值之前,甚至可能不会查询数据库

至于是否有一种“更好”的方法来做这件事,还不可能说。你还没有定义“更好”。就我个人而言,我倾向于选择第二个例子……为什么在需要数据之前将其物化?但在某些情况下,您确实希望强制实现。这取决于场景。

阅读

延迟执行是linq固有的众多奇迹之一。简短的版本是,您的数据永远不会被触动(它在源代码中保持空闲,无论是在内存中,还是在数据库中,或者其他任何地方)。构造linq查询时,您所做的只是创建一个“能够”枚举数据的IEnumerable类。直到您真正开始枚举,然后每段数据都从源代码通过管道一路来,并由您的代码一次一项地提供服务,这项工作才开始。如果您提前中断循环,则保存了一些工作-以后的项目将永远不会被处理。这是一个简单的版本

某些linq操作无法以这种方式工作。Orderby就是最好的例子。Orderby必须知道每一条数据,因为从源代码中检索到的最后一条数据可能是您应该得到的第一条数据。因此,当orderby之类的操作在管道中时,它实际上会在内部缓存数据集。因此,所有数据都已从源中提取出来,并经过管道,一直到orderby,然后orderby成为表达式中后续任何操作的新临时数据源。即便如此,orderby还是会尽可能地遵循延迟执行范式,直到最后一刻才构建缓存。在查询中包含orderby仍然不会立即执行任何工作,但是一旦开始枚举,工作就开始了

要直接回答您的问题,您打电话给ToList就是这么做的。OrderByDescending正在缓存数据源=>ToList中的数据,并将其保存到一个变量中,您可以实际触摸该变量(reviews)=>其中开始从reviews中一次提取一条记录,如果匹配,则最后的ToList调用将结果存储到内存中的另一个列表中

除了内存影响之外,ToList还阻止了延迟执行,因为它还在调用时停止对视图的处理,以完全处理整个linq表达式,从而构建结果的内存表示

现在,如果我们谈论的记录数量是几十张,那么这些都不是什么大问题。在运行时,您永远不会注意到这种差异,因为它发生得太快了。但是,在处理大规模数据集时,尽可能长时间地延迟,希望发生一些事情,允许您取消完整的枚举。。。除了节省内存之外。。。黄金

在没有ToList的版本中:OrderByDescending仍将缓存通过管道处理的数据集副本,当然是在内部进行排序。没关系,你得做你该做的。但直到您稍后在视图中实际尝试检索第一条记录时,这种情况才会发生。一旦该缓存完成,您将获得第一条记录,对于从该缓存中提取的下一条记录,根据where子句进行检查,您将获得该记录,或者不基于where,并且已保存了两个内存副本和大量工作

神奇的是,我敢打赌,在视图开始枚举之前(如果不使用ToList),您的
db.Products.Find(id)
导入甚至都不会开始旋转。如果db.Products是一个Linq2SQL数据源,那么您指定的每个其他元素都将被简化为SQL冗余,并且您的整个表达式将被延迟

希望这有帮助!进一步阅读延迟执行。如果你想知道它是如何工作的,可以看看c#迭代器(yield-return)。在MSDN的某个地方有一个页面,我很难找到它包含常见的linq操作,以及它们是否延迟执行。如果我能找到,我会更新的

/*编辑*/以澄清-以上所有内容都在原始linq或LINQ2对象的上下文中。直到我们找到那一页,常识
List<UserReview> reviews = Model.UserReviews.OrderByDescending(ur => ur.Date).ToList();
if (myUserReview != null)
    reviews = reviews.Where(ur => ur.Id != myUserReview.Id).ToList();
IEnumerable<UserReview> reviews = Model.UserReviews.OrderByDescending(ur => ur.Date);
if (myUserReview != null)
    reviews = reviews.Where(ur => ur.Id != myUserReview.Id);