我flummoxed。意外的IQueryable <>值爲ForEach迭代後
我使用VB.Net,Linq和DataContext。我的DataContext包含一個表「交易」。
我首先聲明一個IQueryable(Of transaction)並將它分配給任何東西。我在foreach循環中構建謂詞並使用transactions.Where(謂詞)爲IQueryable賦值。如果我做了一個IQueryable.ToList(),我得到了集合中的許多項目。
但是,在循環的下一次迭代中,IQueryable.ToList()會給我0個項目。
這讓我瘋狂。我試圖用VS2010使用LINQ to SQL Debug Visualizer,(我用新引用重新編譯了2008版本),但沒有骰子 - 我看不到SQl生成或IQueryable內部有什麼。
下面的代碼:
Dim groupQuery As IQueryable(Of transaction) = Nothing
For Each chosenCode As BillingCode In chosenGroup.BillingCodes
Dim testRun As List(Of transaction) = Nothing
If Not groupQuery Is Nothing Then
testRun = groupQuery.ToList()
End If
Dim codePredicate = PredicateBuilder.True(Of transaction)()
codePredicate = codePredicate.And(Function(i) i.code.Equals(chosenCode.Code))
If Not chosenCode.Description Is Nothing Then codePredicate = codePredicate.And(Function(i) i.description.ToUpper().Contains(chosenCode.Description.ToUpper()))
If Not chosenCode.Insurance Is Nothing Then codePredicate = codePredicate.And(Function(i) i.v_patient.insname.ToUpper().Contains(chosenCode.Insurance.ToUpper()))
If Not chosenCode.PriceFloor Is Nothing Then codePredicate = codePredicate.And(Function(i) i.charge >= chosenCode.PriceFloor)
If Not chosenCode.PriceCeiling Is Nothing Then codePredicate = codePredicate.And(Function(i) i.charge <= chosenCode.PriceCeiling)
Dim testRun2 As List(Of transaction) = Nothing
Dim testRun3 As List(Of transaction) = Nothing
If groupQuery Is Nothing Then
groupQuery = vf.transactions.Where(codePredicate)
Else
testRun2 = groupQuery.ToList()
groupQuery = groupQuery.Union(vf.transactions.Where(codePredicate))
testRun3 = groupQuery.ToList()
End If
Next
我會很感激的任何幫助。謝謝。
編輯:'testRun'變量僅供我調試代碼。我試圖做的是groupQuery = groupQuery.Union(QUERY FROM THIS ITERATION)
而不執行查詢,直到我在代碼中轉換了幾次。對困惑感到抱歉。
回答編輯:我收到的兩個答案都有助於最終的解決方案。我最終都在每次迭代中調用ToList()
,並使用Concat()
而不是Union()
。我發現每次運行Union()
時,生成的SQL都會包含chosenCode
該迭代的參數(@variable
)。在運行查詢時,我可能會在生成的SQL中有10或20組參數(每次迭代爲chosenCode
一組),但只有最後一組參數在運行時提供給SQL Server。不要問我爲什麼。這甚至沒有被證明,只是通過實驗得出的結論。一旦我明白了這一點,我無法弄清楚如何讓所有的參數通過。所以,我放棄了並且在chosenCode
的每次迭代中將查詢運行到SQL Server。我仍然想知道如何在不完成構建之前運行查詢。
而不是在IQueryable
上工作,我使用強類型List(Of transaction)
來存儲ToList()
的結果。然後我在我的代碼的其餘部分使用Linq to Objects來處理這個列表。
我還發現,使用Union()
會在生成的SQL中生成UNION
語句,但這並沒有給我預期的結果。因此,我使用了Concat()
,它在生成的SQL中生成了一條UNION ALL
語句,這正好給了我後面的內容。
謝謝,給大家的幫助。下面的代碼:
For Each chosenGroup As BillingGroup In chosenGroups
Dim groupResults As List(Of transaction) = Nothing
For Each chosenCode As BillingCode In chosenGroup.BillingCodes
Dim codePredicate = PredicateBuilder.True(Of transaction)()
codePredicate = codePredicate.And(Function(i) i.code.Equals(chosenCode.Code))
If Not chosenCode.Description Is Nothing Then codePredicate = codePredicate.And(Function(i) i.description.ToUpper().Contains(chosenCode.Description.ToUpper()))
If Not chosenCode.Insurance Is Nothing Then codePredicate = codePredicate.And(Function(i) i.v_patient.insname.ToUpper().Contains(chosenCode.Insurance.ToUpper()))
If Not chosenCode.PriceFloor Is Nothing Then codePredicate = codePredicate.And(Function(i) i.charge >= chosenCode.PriceFloor)
If Not chosenCode.PriceCeiling Is Nothing Then codePredicate = codePredicate.And(Function(i) i.charge <= chosenCode.PriceCeiling)
If groupResults Is Nothing Then
groupResults = vf.transactions.Where(codePredicate).ToList()
Else
groupResults.AddRange(vf.transactions.Where(codePredicate).ToList())
End If
Next
感謝您的意見!我其實確實想要做一箇舊的selectedCode和新的selectedCode的聯合。另外,如果我執行'ToList()',恐怕查詢將執行導致對SQL Server的不必要的調用。我錯了嗎? – ffrugone 2012-04-15 20:36:00
它可能是簡化代碼的人工產物,但它看起來像是一種非常複雜的導致1執行的方式。 – 2012-04-15 21:06:19
噢,夥計。我知道這麼少。我不知道什麼是1次執行。但是,我可以解釋一下情況。 foreach的每次迭代都會生成插入到查詢中的動態謂詞。每個查詢都是聯合在一起的。然後在外部的foreach中,UNION的查詢首先被分組,然後UNION與其他人一樣。然後,再次進行過濾,最後再進行分組。 – ffrugone 2012-04-15 21:18:06