【问题标题】:Using Linq to return the count of items from a query along with its resultset使用 Linq 从查询中返回项目数及其结果集
【发布时间】:2013-04-29 05:16:40
【问题描述】:

我正在使用带有 Linq 的 C# MVC4。

我为我的项目使用了依赖注入,这导致我拥有一个单独的模型项目以及一个单独的存储库项目(以及一个用于测试等)。这一切都没有问题。

我将查询从控制器(旧样式)移到存储库(新 DI 样式)中,然后注入它们。它工作正常。

我有一个标准的 linq 查询(选择任何示例,它们都足够基本),它正常地从数据库中返回一组项目。这里也没有问题。

我的问题是,我想实现分页,而且我教它很简单。这是我的步骤:

从存储库中获取 linq 查询的结果(注入到控制器中)将其存储在 var 中。它看起来像:

var results = _someInjectedCode.GetListById(SomeId);

之前,我可以做一些简单的事情,比如:

results.Count()
results.Skip(SomeNum).Take(SomeOtherNum)

但是现在我想要分页,我需要像这样执行我的 Skip Take 操作:

var results = from xyz in _someInjectedCode.GetListById(SomeId).SomeId).Skip(SomeNum).Take(SomeOtherNum)
select new[] {a,id, a.fName, a.lName .....}

这样做的问题是,在列表缩短到 Pre Skip...Take 状态之前,我不再有权访问项目的总数,除非我执行两个查询,这意味着两次访问数据库。

解决此问题的最佳方法是什么。

【问题讨论】:

    标签: c# asp.net-mvc linq


    【解决方案1】:

    我只是这样做:

    var result = (from n in mycollection 
                  where n.someprop == "some value" 
                  select n).ToList();
    var count = result.Count;
    

    可能还有其他方法,但这是我所知道的最简单的方法。

    【讨论】:

    • 使用您的解决方案,我得到了一些工作,而无需对数据库进行 2 次调用。但正如 Joe Enos 所建议的那样,它的内存密集度更高。但是,目前,我只需要一些有效的东西,而这确实有效。本质上,我将 DI 存储库的结果分配给了一个变量。对它进行了计数,然后使用内存中的变量进行了跳过。我只希望我们不要检索 500 万条记录。 :) 谢谢。
    • 错过了,被拒了,不过这里值得一提。一位匿名用户建议您可以通过删除 ().ToList() 并在结果上执行 Count() 来获得相同的结果。不对。这样做会使 result 成为 IQueryable 并且 Count() 方法将执行查询,只返回计数而不是数据。此处包含非常重要的知识。
    【解决方案2】:

    从 SQL 的角度考虑,我想不出在单个普通查询中检索总计数和数据子集的方法,所以我认为您无法也可以在 LINQ 中进行。

    为了避免创建两个单独的命令,我唯一能想到的是一个存储过程,它返回两个表(一个只包含计数,另一个包含结果子集)。它仍然会执行两个查询,但在一个连接中。你会失去你的LINQ。所以如果你想保留你的 LINQ 查询,你可能会被困在进行两个单独的调用。

    另一种方法是将整个未分页的结果集检索到内存中,然后对数组运行 TakeSkip,但这非常浪费,可能比两次调用更糟糕。

    【讨论】:

    • 遗憾的是我不能使用链轮(数据库管理员不会让我们)。但除此之外,这是一个有效的选择。现在唯一的问题是,效率“较低”,将结果集加载到内存中,进行计数,然后在那里跳过它,或者进行第二次查询,因为我必须保留 linq。谢谢你的回答。
    • 取决于您的结果集的大小,但我猜打 2 个电话几乎总是更好。如果您一次翻 10 页并且有 100 页,那么为了扔掉它们而额外获得 90 页显然是一种浪费。但是这个数字是你必须测试的——我的猜测是在 30 左右。但实际上,2 个调用确实不错——通常在普通应用程序中每个 Web 请求都会有多个 DB 调用,所以除非你'在每一个可能的纳秒之后,你永远不会注意到这一点。此外,代码会更简洁、更一致,因此您和未来的开发人员会在以后欣赏它。
    • 感谢您的帮助。
    【解决方案3】:

    您可以向存储库接口/类添加其他参数,这些参数将提供分页参数并在结果旁边返回计数,或者修改接口以返回 IQueryable,然后应用计数,然后在编译查询并发送执行之前跳过/获取.

    【讨论】:

    • 感谢您的回答。虽然有点复杂,但我确实认为从长远来看这是做事的正确方法。我选择了另一个答案,因为它为我的问题提供了快速解决方案。但这不是最好的解决方案。我认为你的是最好的。问题是我现在还不完全理解如何实现它,所以我必须采用另一个答案。不过,当我有时间时,我会对此做进一步的研究,以便下次我能做得更好。感谢您的帮助。
    • 没问题。但是我必须警告您,您选择的解决方案对我来说似乎是错误的。当您在数据库中有 100 条记录时,您可以调用 ToList 然后获取计数(列表的!)。分页将应用于列表(而不是查询)。想想每次执行查询时都会将数据库查询中的 200 万个项目加载到对象中。对于额外的 db 调用来说,这是相当不公平的补偿。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 1970-01-01
    • 2013-03-26
    • 1970-01-01
    相关资源
    最近更新 更多