注意:我在查询中使用了实体框架“上下文”。答案适用于实体框架或 LINQ-to-SQL。
ToArray() 和 ToList() 永远不会加快查询速度。但是,如果您不小心多次运行查询,它们可能会以这种方式显示。这是使用 LINQ 时的常见错误。例如:
// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
上面的行实际上并没有查询数据库中的可爱小狗。相反,它构建了一个查询,该查询将在未来某个时候查询小狗。这称为延迟执行。测验问题:上例中的“数据”是什么类型?
当您枚举变量数据时,查询实际上是运行的。此变量的类型为 IEnumerable。IEnumerables 不同于列表或数组。IEnumerable 仅仅是一个可以获取数据的承诺。这并不意味着您实际上拥有数据。
// Display the puppies
foreach (Puppy p in data) { Console.WriteLine(p.Name); }
上面的 foreach 调用将强制执行查询。小狗将进入屏幕,但它们不会被缓存在任何地方的数组或列表中。所以现在,如果你这样做:
// Display their owner's names
foreach (Puppy p in data) { Console.Writeline(p.OwnerName); }
这个 foreach 导致查询再次执行。事实上,如果在两次调用之间在数据库中添加或删除了新的小狗,您甚至可能得到不同的结果!所以假设相反,我们将 ToList() 添加到初始调用中。
// Construct a query to find all the cute puppies
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
现在,数据是列表类型。在后台,这会创建一个 IEnumerable,然后通过它执行 foreach,并将结果放入列表中。所以现在,如果你显示小狗的名字和主人,它不会两次查询数据库。相反,它在列表中循环两次。
如果您搜索延迟执行,您会发现很多有趣的用途,以及我列出的警告。通常,您要确保只运行一次查询。如果这需要 ToList() 那就太好了。但不要不必要地添加 ToList() 。使用最后一个示例:
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
foreach (Puppy p in data) { Console.WriteLine(p.Name + "," + p.OwnerName); }
你应该在这里有 ToList() 吗?不!因为当您确实不需要列表时,这会增加列表的开销。更糟:
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute).ToList();
Console.Writeline(data.Count());
那更糟!它把所有的小狗都拉到内存中的一个列表中,然后对它们进行计数。但这个查询甚至根本不需要抓住小狗。这样做:
var data = myContext.Puppies.Where(puppy => puppy.Type == PuppyTypes.Cute);
Console.Writeline(data.Count());
它实际上告诉 SQL 服务器计算小狗的数量,并且永远不会浪费带宽或内存,实际上将小狗从数据库中加载出来或将其发送到 C# 或任何其他地方。
我希望这有帮助!