【问题标题】:The query results cannot be enumerated more than once?查询结果不能枚举多次?
【发布时间】:2011-11-09 04:47:52
【问题描述】:

我正在使用 LINQ to SQL 在 Sql server 2008 中获取 FullTextSearch 存储过程的搜索结果。我将该过程从服务器资源管理器拖到设计器中,并获得了使用适当的返回类型和参数创建的方法。现在的问题是,我需要获取调用此方法的结果的计数,因此使用我的存储库方法(它将调用 Sproc 方法并将结果作为 IQueryable 返回)我进行了以下调用。

var result = repository.FullTextSearch(searchText);
        int resultsCount = result.Count();
        var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList();

此代码每次尝试运行时都会生成一个 InvalidOperationException,异常显示(是的,您猜对了!)“查询结果不能多​​次枚举。”

为 Sproc 生成的方法返回 ISingleResult,它应该是正常的。 AFAIK。我需要在我的视图上支持分页,所以我需要知道总页数,这(再次是 AFAIK)只有在我可以获得所有项目的计数时才有可能。

我在这里错过了什么,伙计们?

【问题讨论】:

  • 显然 Marc Gravell 建议的重构是最好的,一旦我有时间就去做。我接受马克的回答!再次感谢伙计们!

标签: linq-to-sql invalidoperationexception


【解决方案1】:

您可以在repository.FullTextSearch(searchText) 之后添加一个ToList() 调用。这样,结果将从服务器检索,之后您可以随心所欲地使用它们(因为它们现在已加载到内存中)。

您现在尝试做的是两次运行相同的 SQL 查询,这是相当低效的。

【讨论】:

  • 我认为将整个 FTS 结果返回并实现所有内容基本上比运行两个(但受限制的)查询效率低。
  • 马克我也这么认为。我的意思是,如果我按照您的建议添加 .ToList() rwwilden,那么我将获得整个搜索结果,这可能是巨大的。我现在不想全部得到它们,我只想要其中的 10 个,这就是我使用 .Skip()ping 的原因。
  • 我同意将整个结果集返回服务器比执行两个查询效率低。但是,由于它是一个存储过程调用,无论如何都会发生(正如 Marc 在他的回答中正确指出的那样)。
  • 是的,你是对的 rwwilden,我完全忘记了 sproc 结果集将如何被急切地带来。我站得更正了。谢谢+1
  • 在一次往返中进行计数和页面绝对是最好的解决方案。当然需要对你的存储过程进行一些重写。
【解决方案2】:

由于这是执行一个存储过程,所以你所有可爱的Skip / Take 在很大程度上都是多余的......它别无选择,只能将所有数据带回来(存储过程调用是不可组合的)。它唯一能做的就是不为其中一些对象具体化。

我想知道更好的方法是重构代码以进行两次调用:

int result = repository.FullTextSearchCount(searchText);
var result = repository.FullTextSearch(searchText, skip, take); // or similar

即使分页参数成为 SPROC 的一部分(以及在数据库中进行过滤,使用 ROW_NUMBER() / OVER(...) 或表变量、临时表等) - 或者与 OUTPUT 参数类似的东西存储过程:

int? count = null;
var result = repository.FullTextSearch(searchText, skip, take, ref count);

(我好像记得OUTPUT变成了ref,因为TSQL OUTPUT真的是输入+输出)

【讨论】:

  • 完全同意这里的重构部分,但是,现在时间不允许。现在我想我将向存储库“int FullTextSearchCount()”添加另一种方法。这似乎在我说话时起作用。重构技巧在 To-Do now Marc 上。 +1 谢谢。
【解决方案3】:

使用ToList() 可以帮助避免这个问题。

var result = repository.FullTextSearch(searchText).ToList();

【讨论】:

    【解决方案4】:

    我建议如果您需要计数,请先执行结果。然后从列表本身运行计数,因为您在结果执行中不使用 resultsCount。

    var result = repository.FullTextSearch(searchText);
    var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList();
    int resultsCount = ret.Count();
    

    【讨论】:

    • 思路是resultsCount代表结果的总数。
    • 是的,卡马尔!我需要得到所有结果的计数。不仅是我要参加的部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多