1

我有一个扩展方法,可以同时对IEnumerable和进行操作IQueryable。该方法最终解析输入和调用Skip().Take()

public static IEnumerable<T> SelectRange<T>(
    this IEnumerable<T> target,
    RangeHeaderValue range
    )

此方法适用于 anIQueryable但它返回一个IEnumerable. 所以我添加了另一种方法进行转换,调用第一种方法并再次转换:

public static IQueryable<T> SelectRange<T>(
    this IQueryable<T> target,
    RangeHeaderValue range
    )
{
    return target.AsEnumerable().SelectRange(range).AsQueryable();
}

像这样链式转换是否安全?我担心它可能会干扰提供IQueryable程序,而是在内存集合上运行该方法。我了解延迟/急切加载的基础知识,但这是一个相当复杂的主题,我不想只是假设它会起作用。


注意:关于链接的危险,公认的答案是正确的,但我想补充一点,实现该IQueryable方法并从该方法调用它IEnumerable(因此只需切换事物)是安全的。

4

2 回答 2

8

不; 这不是一个好主意。

调用AsEnumerable()将实现整个查询,然后Skip()Take()客户端上运行。

您需要制作一个单独(且相同)的方法版本,该版本IQueryable<T>只调用 Queryable 方法,以便查询可以在服务器上运行。

于 2013-08-12T11:48:32.353 回答
1

简短的回答:也许

AsEnumerable() 可能会实现您的查询。找出答案的最简单方法是获取SQL Server Express Profiler并并排调试,以查看查询何时被调用。事实上,IQueryable继承自IEnumerable.

此外,在调试时:如果您尝试查看发生了什么,IDE 可能会将其具体化以在漂亮的 VS 浮动 GUI 调试工具中显示它

根据我的经验:在我调用 an或任何其他继承自的之前,从AsEnumerable()to来回跳转AsQueryable()不会实现它,但请记住,这会使内存中的计算类似于 Graph。因此,即使您实际上没有看到它对数据库进行查询,在内存较低的级别上,您也可能会考虑一些性能成本。ToArray()ToList()ICollectionIQueryable

和你一样,我试图避免在我的Repository Pattern中生成重复,特别是在分页时:

public static class Paginate
{
    public static IEnumerable<T> Enumerable<T>(int records, int iPage, IEnumerable<T> input) where T : class { return input.Skip(records * iPage).Take(records); }

// My internal OCD hates this dup >.o
    public static IQueryable <T> Queryable <T>(int records, int iPage, IQueryable <T> input) where T : class { return input.Skip(records * iPage).Take(records); }
}

但我最终这样做是为了避免一个问题,这个问题会让我整个上午都在追逐一个被上帝遗弃的虫子,最终陷入死胡同,面对贴在墙上的一条消息,写着“我告诉你如此”

于 2013-12-18T21:08:03.003 回答