2016-04-19 111 views
2

使用Linq to Entities,当我对用书写的LINQ语句创建的Linq对象执行Where lamba表达式时,where子句不工作。Where子句不适用于LINQ IQueryable查询

这不起作用。查询执行,但结果未经过滤返回。

var myQuery = (from l in db.MyTable 
        select l); 
myQuery.Where(r => availableStatusList.Contains(r.Status)); 
var myObj = myQuery.ToList(); 

这是行不通的。查询执行,AND结果返回正确过滤。

var myQuery = (from l in db.MyTable 
        select l).Where(r => availableStatusList.Contains(r.Status)); 
var myObj = myQuery.ToList(); 

据我所知,这两个应该返回相同的结果。为什么第一个人不听Where条款?

+3

你没”把它分配回myQuery。 Where子句创建一个新的对象,它不会改变现有的对象。 –

+0

尝试把'where'换成原始格式(不是从标准格式到内联格式):从db.MyTable中的l where availableStatusList.Contains(l.Status)select l ;.我很好奇,看看它是否会改变它。 – BlackjacketMack

回答

5

A Where子句在调用时不会创建新对象;它通过将集合包装在最终将运行的过滤器中来将过滤器应用于现有集合。但是,由于它是一个纯函数,因此该过滤器的返回值需要返回到原始参考myQuery,这就是为什么第二个示例正常工作的原因......您已将结果通过Where()子句链接回myQuery。您返回已过滤的集合,使用ToList()实现延迟查询。

在第一个示例中,假设过滤器直接应用于集合,但这不是LINQ的工作方式,因为过滤器在调用函数时不会立即修改集合。相反,它只应用一个谓词,只要它被“附加”到原始的Queryable集合上并且您用ToList()解决了查询。

将延期执行视为一系列承诺有时会更容易。

如果我给你一美元,你有一美元。如果我拿25美分的税,我已经立即解决了我们的交易(查询)。

但是,如果我保证在星期二给你一美元,我已经退回Queryable<T>承诺

现在和周二之间可能会发生多个事件。我可以链接一个过滤器(25美分),一个口香糖过滤器(25美分)或任何其他过滤器。

但是,我们的簿记系统有一个警告。我们不能只在总承诺金额上拨打.Taxes()(我们的Where条款),并期望其更新。我们必须记录我们的交易与承诺金额相比,将过滤器返回到原始变量,并使用与我们承诺的金额相对应的交易进行更新。

myQuery = myQuery.Where(condition); 

上周二,当你来收集您的付款(通过对一系列链式承诺/过滤器的调用ToList()),我已经扣除从什么是承诺,造成了50%的支出发生了什么。这是延迟执行工作。

+1

我认为'Where'子句实际上会返回一个新的可枚举,过滤等。 var list = new List {“hi”,“bye”}; Assert.AreNotSame(list,list.Where(w => w ==“hi”)); – BlackjacketMack

+1

@BlackjacketMack IEnumerable不是IQuerable。更新了重点答案。另外,你的比较是无效的。您的比较类型的列表类型为IEnumerable,这是无效的。它们不是相同的类型,虽然底层的集合没有改变。如果我们正在谈论“对象”的参考,是的,一个新的参考被创建。如果我们正在使用底层集合来谈论“对象”,否则不会创建新集合并返回,直到查询实现为止。 –

+0

我看到...所以IQueryable不断得到修改,但保留了相同的参考?所以如果我要添加额外的子句Assert.AreSame()会传递?我的印象是,像IEnumerables一样,每个附加的linq子句都会返回一个新的和不同的IQueryable,作为一个装饰者会有意识地包装前面的语句。 – BlackjacketMack

3

较短的答案:

为字符串赋值函数功能类似,您需要分配回变量:

string sample = "text"; 

// this doesn't change sample 
sample.ToUpper(); 

// this one does 
sample = sample.ToUpper(); 

所以,你需要的是:

myQuery = myQuery.Where(...)