C# 在linq中混合数据库和对象查询并提供分页结果

C# 在linq中混合数据库和对象查询并提供分页结果,c#,linq,entity-framework,C#,Linq,Entity Framework,我需要建立一个查询,提供分页结果。过滤的一部分发生在数据库中,另一部分发生在内存中的对象中 下面是一个简化的示例,它显示了我可以做什么,即对数据库运行linq查询,然后使用自定义代码对其进行进一步筛选,然后使用skip/take进行分页,但这将非常低效,因为它需要加载与查询的第一部分匹配的所有项 Things.Where(e=>e.field1==1 && e.field2>1).ToList() .Where(e=>Helper

我需要建立一个查询,提供分页结果。过滤的一部分发生在数据库中,另一部分发生在内存中的对象中

下面是一个简化的示例,它显示了我可以做什么,即对数据库运行linq查询,然后使用自定义代码对其进行进一步筛选,然后使用skip/take进行分页,但这将非常低效,因为它需要加载与查询的第一部分匹配的所有项

    Things.Where(e=>e.field1==1 && e.field2>1).ToList()
            .Where(e=>Helper.MyFilter(e,param1,param2)).Skip(m*pageSize).Take(pageSize);
MyFilter函数使用不在数据库中的其他数据,并使用其他参数运行(上例中的paramX)


是否有更好的方法来处理这种情况,而不将初始结果完全加载到内存中。

是,在数据库级别进行查询和分页。Helper.MyFilter中的任何逻辑都需要在sql查询中


另一个选项对您的代码库更具侵入性。是在实体更改时保存视图模型以及域实体。视图模型的一部分将包含Helper.MyFilter(e)的结果,因此您可以快速有效地查询它。

为了支持上面Jason的答案,entity framework支持.Skip().Take()。因此,将其发送到db级别,并将您的where转换为EF可以使用的内容

如果您的where助手很复杂,请使用Albahari的谓词生成器:

或者更易于使用的通用谓词生成器:

基于上述

.ToList()
您正在将查询转换为内存对象,即列表,从而导致执行查询,然后对数据进行分页

您可以将其全部放在一个
Where
子句中:

Things.Where(e=>e.field1==1 && e.field2>1
            && e=>Helper.MyFilter(e)).Skip(m*pageSize).Take(pageSize);
然后
.ToList()
。 这样,您将给LINQtoSQL一个机会来生成查询,并只获取所需的数据

或者,您之所以要这样做,有一个特殊的原因——转换为内存对象,然后进行过滤?虽然我看不出重点。在对数据库实际执行LINQtoSQL查询之前,应该能够过滤掉不希望在LINQtoSQL查询中出现的结果

编辑

正如我从讨论中看到的,你有几个选择

如果您有很多数据,并且读的比写的多,那么如果可能的话,最好在插入时将
Helper.MyFilter
的结果保存到数据库中。这样,您就可以提高select的性能,因为您不会从数据库中提取所有数据,而且
select
本身也会有一个更过滤的数据


或者你可以采取另一种方法。您可以将
Helper
类放入一个单独的程序集中,然后单击。这将使您能够将分页逻辑放入数据库中,并使用代码

这假设可以将
Helper.MyFitler(e)
中的逻辑转换为sql。正如Jason提到的,这将不起作用,因为函数包含无法转换为sql的代码。这就是为什么我用ToList@cellik-你必须按正确的顺序做每件事吗?我在想,也许您可以通过重新排序来“部分优化”查询:。其中(e=>e.field1==1&&e.field2>1)。跳过(m*pageSize)。获取(pageSize)。其中(e=>Helper.MyFilter(e))如果我这样做,我获取的项目数可能小于我的页面大小,因为我在执行第一个选项后应用了其他筛选器。您的第一个选项不可能,因为MyFilter函数使用了一些数据库中没有的其他信息。保存MyFilter的结果是不可行的,因为MyFilter实际上有额外的参数。我已经相应地更新了这个问题。如果您将MyFilter的结果保存在db中,那么无论它是如何计算的,只是它是。但您是在更改实体时保存的,而不是在查询数据库时保存的。如果您在数据库之外有需求,则无法在数据库中分页结果,因此必须在分页之前将结果加载到内存中。它必须确实加载到内存中,但不能仅加载其中的一部分吗?我想加载db过滤数据的页面,应用内存中的辅助过滤器,如果结果小于我的实际页面大小,则继续从数据库中获取更多数据。这在第一页是可以的,但是在那之后会变得很棘手。