链接AsEnumerable和AsQueryable是否安全

本文关键字:是否 安全 AsQueryable AsEnumerable 链接 | 更新日期: 2023-09-27 18:27:15

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

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

此方法适用于IQueryable,但它返回一个IEnumerable。所以我添加了另一个方法来转换,调用第一个方法并再次转换:

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

这样链式转换安全吗?我担心它可能会干扰IQueryable提供程序,而是在内存中的集合上运行该方法。我理解懒惰/渴望加载的基本原理,但这是一个相当复杂的主题,我不想只是假设它会起作用。


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

链接AsEnumerable和AsQueryable是否安全

否;这不是一个好主意。

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

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

简短的答案:也许

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

此外,在调试时:如果你想看看发生了什么,IDE可能会将其具体化,并在漂亮的VS浮动GUI调试工具中显示出来

根据我的经验:从AsEnumerable()AsQueryable()的来回跳跃直到我调用ToArray()ToList()或任何其他从ICollection继承的东西才实现,但请记住,IQueryable在内存中保持类似于Graph的计算。因此,即使您实际上没有看到它在数据库中进行查询,在内存较低的情况下,您可能会看到一些性能成本。

和你一样,我试图避免在存储库模式中生成重复数据,特别是在分页时:

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); }
}

但我最终这样做是为了避免出现一个问题,这个问题会让我整个上午都在追逐一只被上帝遗弃的虫子,最终陷入死胡同,我会面对墙上贴着的一张纸条,上面写着"我早就告诉过你了"