C#LINQ反复执行相同的工作

FBryant87

遇到了一些传统代码,其中逻辑试图阻止对昂贵的查询的不必要的多次调用GetStudentsOnCourse(),但由于对延期执行的误解而失败。

var students = studentsToRemoveRecords.Select(x => x.CourseId)
                    .Distinct()
                    .SelectMany(c => studentRepository.GetStudentsOnCourse(c.Value));


var studentsToRemove = new List<Student>();

foreach (var record in studentsToRemoveRecords)
{
    studentsToRemove.Add(
        students.Single(s => s.Id == record.StudentId));
}

在这里,如果中有2条相同课程的记录,则studentsToRemoveRecords该查询GetStudentsOnCourse()将被不必要地调用两次(具有相同的课程ID),而不是一次。

您可以通过以下方法解决此问题:students预先转换为列表,然后将其强制进入内存(防止延迟执行)。或者通过简单地将逻辑重写为一些简单的东西。

但是后来我意识到,我实际上很难说出GetStudentsOnCourse()在上述情况下为什么被两次调用的确切原因...难道LINQ每次studentsToRemoveRecords迭代都重复相同的工作,即使每次得到的输入值都是相同的?

托本·施拉姆

即使每次生成的输入值都相同,LINQ还是在每次迭代StudentToRemoveRecords时都重复相同的工作吗?

是的,这就是LINQ的本质。一些Visual Studio扩展(例如ReSharper)在创建代码时会向您发出警告,这些代码可能导致LINQ查询的多次迭代。

如果要避免这种情况,请执行以下操作:

var students = studentsToRemoveRecords.Select(x => x.CourseId)
                .Distinct()
                .SelectMany(c => studentRepository.GetStudentsOnCourse(c.Value))
                .ToList();

使用ToList()Query可以立即执行,并将生成的实体存储在中List<T>现在,您可以进行多次迭代students而不会出现性能问题。

编辑以包含评论:

这里是一些很好的文档链接(谢谢Sergio):LINQ文档

关于如何在大型代码库中处理此问题的一些想法:嗯,两种情况都有其原因-直接执行并将结果存储到新列表中,以及推迟执行。如果您熟悉SQL数据库,则可以将LINQ查询看作是视图或存储过程。您可以定义要在基表上执行哪些筛选/更改以获取结果实体。并且,每当您查询该“查看/执行该存储过程”时,该存储过程便会基于基表中的当前数据运行。

LINQ也一样。您的查询(不带ToList())就像视图的定义一样。而且,每次您对其进行迭代时,该定义都将基于当时的当前实体执行studentsToRemoveRecords也许那是你的想法。也许您知道此基本列表正在更改,并且您想多次执行查询,期望得到不同的结果。然后不做ToList()

但是,如果您只想执行一次查询,然后期望一个不可变的结果列表,您可以在该列表上进行多次迭代,请使用ToList()

因此,两种情况都有效。而且,当您仅迭代一次时,两种情况都是相同的(免责声明:在定义查询后直接进行迭代)。也许这就是为什么您如此多次看到它的原因。这取决于您想要什么。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章