C# - 在内存中连接IList和IQueryable?

时间:2016-05-06 03:31:44

标签: c# linq list iqueryable

假设我有一个包含一个字符串值的List。假设我还有一个IQueryable,它包含数据库中的几个字符串。我希望能够将这两个容器连接成一个列表,然后能够在列表中调用诸如.Skip或.Take之类的方法。我希望能够以这样的方式执行此操作:当我将两个容器组合时,我不会将所有数据库数据加载到内存中(仅在我调用.Skip和.Take之后)。基本上,我想做这样的事情(伪代码):

IQueryable someQuery = myEntities.GetDBQuery(); // Gets "test2", "test3"
IList inMemoryList = new List();
inMemoryList.Add("test");

IList finalList = inMemoryList.Union(someQuery) // Can I do something like this without loading DB data into memory? finalList should contain all 3 strings.

// At this point it is fine to load the filtered query into memory.
foreach (string myString in finalList.Skip(100).Take(200))
{
   // Do work...
}

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:2)

如果我没有误解,你试图查询数据,其中一部分来自内存,另一部分来自数据库,如下所示:

//the following code will not compile, just for example
var dbQuery = BuildDbQuery();
var list = BuildListInMemory();
var myQuery = (dbQuery + list).OrderBy(aa).Skip(bb).Take(cc).Select(dd);
//and you don't want to load all records into memory by dbQuery 
//because you only need some of them

简短的回答是不,你不能。考虑.OrderBy方法,所有数据必须位于相同的“位置”,否则代码无法对它们进行排序。因此,代码将dbQuery中的所有记录加载到内存中(现在它们位于同一位置),然后对所有记录进行排序,包括list中的记录。当dbQuery给出数千行时,这可能会导致内存问题。

如何解决

  1. list中的数据传递到数据库中(作为dbQuery的参数),以便查询在数据库中进行。如果您的list只有几件商品,这很容易。

  2. 如果list还有大量记录会导致dbQuery过于复杂,您可以尝试两次查询,一次查询dbQuery,另一次查看list 。例如,数据库中有10,000个用户,内存列表中有1,000个用户,并且您希望获得前10位最年轻的用户。您不需要将10,000个用户加载到内存中,然后找到最年轻的10.相反,您会在dbQuery中找到10个最年轻的(ResultA)并加载到内存中,并且10个最年轻的(ResultB)在内存列表中,然后比较ResultA和ResultB。

答案 1 :(得分:0)

我完全同意Danny的回答,他说你需要以某种方式找到一种方法将内存用户列表包含到db中,以便你实现你想要的。至于您在评论中寻找的示例,在不知道User对象的数据结构的情况下,似乎很难。但假设您能够连接点。这是我建议的方法:

  1. 创建与数据库中常规用户表相同结构的临时表,并将所有内存用户插入其中
  2. 将一个查询写入Union临时表和常规表,两者结构相同,这样应该很容易。
  3. 将结果返回到您的应用程序中,并使用它执行标准的Linq操作 如果你想要你可以使用的确切代码,那么你必须在db中提供你的用户对象结构 - 字段类型等,以便我能够编写代码。

答案 2 :(得分:0)

您指定查询和列表都是字符串序列。 someQuery可以在数据库端完全执行(不在内存中)

让我们的序列不那么通用:

IQueryable<string> someQuery = ...
IList<string> myList = ...

您还指定myList只包含一个元素。

string myOneAndOnlyString = myList.Single();

由于您的列表在内存中,因此必须在内存中执行。但由于该列表只有一个元素,因此不会花费任何时间。

您请求的查询:

IQueryable<string> correctQuery = someQuery
    .Where(item => item.Equals(myOneandOnlyString)
    .Skip(skipCount)
    .Take(takeCount)

使用SQL Server Profiler检查已使用的SQL,并查看该请求是否在一个SQL语句中完全执行。