2009-09-30 69 views
1

我花費了大量時間試圖弄清楚爲什麼Linq2SQL正在更改我的SQL查詢。這是很難解釋,我找不到任何理由爲什麼發生這種情況。最低限度的是看起來,添加多個包含IQueryable似乎覆蓋了每個以前的IQueryable表達式。讓我試着解釋一下:添加多個包含IQueryable到基礎IQueryable每更改一次前面的IQueryable

假設你有一個Linq2SQL查詢,它提供了查詢的基本框架。 (這是你的所有查詢的基礎)

我動態地添加了部分where查詢(在下面的示例中顯示爲「partQuery」)。從where查詢生成的Expression是正確的,當我將它添加到finalQuery時 - 它仍然是正確的。當我向最終查詢中添加另一個partQuery時,問題就出現了,它似乎覆蓋了最終查詢中的第一個查詢,但向其中添加了第二個查詢。 (或者,如下所示,加入第三個查詢時,將覆蓋第一2個查詢)

下面是一些源例如:

foreach (var partQuery in whereStatements) 
    { 
     finalQuery = finalQuery.Where(
      dataEvent => partQuery.Contains(dataEvent.DataEventID) 
      ); 
    } 

的partQuery是類型的IQueryable finalQuery是查詢,最終將在SQL服務器

 // the list of the wheres that are sent 
     var whereStatements = new List<IQueryable<long>>(); 

     var query1 = DataEvent.GetQueryBase(context); 
     query1 = query1.Where(
      dataEvent => 
      dataEvent.DataEventKeyID == (short)DataEventTypesEnum.TotalDollarAmount && dataEvent.ValueDouble < -50); 

     whereStatements.Add(query1.Select(x => x.DataEventID)); 


     var query2 = DataEvent.GetQueryBase(context); 
     query2 = query2.Where(
      dataEvent => 
      dataEvent.DataEventKeyID == (short)DataEventTypesEnum.ObjectNumber && dataEvent.ValueDouble == 6); 

     whereStatements.Add(query2.Select(x => x.DataEventID)); 

執行的第一其中查詢(QUERY1)具有原來像這樣的表達式:

{SELECT [t0].[DataEventID] 
FROM [dbo].[DataEvents] AS [t0] 
INNER JOIN [dbo].[DataEventAttributes] AS [t1] ON [t0].[DataEventID] = [t1].[DataEventID] 
WHERE ([t1].[DataEventKeyID] = @p0) AND ([t1].[ValueDouble] < @p1) 
} 

注意,其中線具有ValueDouble「<」 @ P1 - 小於

,然後當加入到最終的查詢,它看起來像這樣:

{SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp] 
FROM [dbo].[DataEvents] AS [t0] 
WHERE (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t1] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID] 
    WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] = @p0) AND ([t2].[ValueDouble] < @p1) 
)) AND ([t0].[DataOwnerID] = @p2) 
} 

在這一點上,該查詢仍然正確。請注意ValueDouble如何仍具有「<」符號。當我向查詢添加2個或更多時發生問題。這是第二個查詢在這個例子中,表達式:

{SELECT [t0].[DataEventID] 
FROM [dbo].[DataEvents] AS [t0] 
INNER JOIN [dbo].[DataEventAttributes] AS [t1] ON [t0].[DataEventID] = [t1].[DataEventID] 
WHERE ([t1].[DataEventKeyID] = @p0) AND ([t1].[ValueDouble] = @p1) 
} 

,當添加到最終的查詢..你會發現,第一次查詢不再是正確的......(而且更多的驚喜之後)

{SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp] 
FROM [dbo].[DataEvents] AS [t0] 
WHERE (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t1] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID] 
    WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] = @p0) AND ([t2].[ValueDouble] = @p1) 
)) AND (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t3] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t4] ON [t3].[DataEventID] = [t4].[DataEventID] 
    WHERE ([t3].[DataEventID] = [t0].[DataEventID]) AND ([t4].[DataEventKeyID] = @p2) AND ([t4].[ValueDouble] = @p3) 
)) AND ([t0].[DataOwnerID] = @p4) 
} 

和獎金吧...在此通過SQL事件探查器後看,似乎它完全放棄了第一查詢,這兩個存在於最終的SQL條款實際上是相同的查詢(QUERY2 )。沒有任何參數實際傳遞給SQl服務器進行第一個查詢。

因此,在我對此的研究中,它似乎將SQl的查詢添加到SQl中,但它將所有已存在的where子句替換爲已添加的最後一個。要加倍確認這個..與上面完全相同的代碼,但我添加了第三個查詢....並查看它是如何改變的。

 var query3 = DataEvent.GetQueryBase(context); 
     query3 = query3.Where(
      dataEvent => 
      dataEvent.DataEventKeyID != (short)DataEventTypesEnum.Quantity && dataEvent.ValueDouble != 5); 

     whereStatements.Add(query3.Select(x => x.DataEventID)); 

我在一些扔「!=」到查詢的最後一部分

{SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp] 
FROM [dbo].[DataEvents] AS [t0] 
WHERE (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t1] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID] 
    WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] <> @p0) AND ([t2].[ValueDouble] <> @p1) 
)) AND (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t3] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t4] ON [t3].[DataEventID] = [t4].[DataEventID] 
    WHERE ([t3].[DataEventID] = [t0].[DataEventID]) AND ([t4].[DataEventKeyID] <> @p2) AND ([t4].[ValueDouble] <> @p3) 
)) AND (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [dbo].[DataEvents] AS [t5] 
    INNER JOIN [dbo].[DataEventAttributes] AS [t6] ON [t5].[DataEventID] = [t6].[DataEventID] 
    WHERE ([t5].[DataEventID] = [t0].[DataEventID]) AND ([t6].[DataEventKeyID] <> @p4) AND ([t6].[ValueDouble] <> @p5) 
)) AND ([t0].[DataOwnerID] = @p6) 
} 

通知所有三個內部查詢,現在怎麼都是「<>」,其中上面的查詢是不是。

我完全擺脫了我的搖桿嗎?我是否錯過了這麼簡單的事情,當你告訴我我想要拔掉我的指甲?我實際上希望你告訴我,而不是告訴我,它看起來像MS框架中的錯誤(嗯,我們知道有時會發生)。

任何幫助,非常感謝。也許我應該以不同的方式將動態查詢部分發送到基本查詢。我對想法持開放態度。

回答

3

而不必完全評估你的例子,有一件事突出的是這樣的:

foreach (var partQuery in whereStatements) 
{ 
    finalQuery = finalQuery.Where(
     dataEvent => partQuery.Contains(dataEvent.DataEventID) 
     ); 
} 

的因爲這個循環的結構方式,在每次迭代中生成的每一個表情,最終使用的partQuery終值 - 循環終止時存在的值。你可能想要這個,而是:現在

foreach (var partQuery in whereStatements) 
{ 
    var part = partQuery; 
    finalQuery = finalQuery.Where(
     dataEvent => part.Contains(dataEvent.DataEventID) 
     ); 
} 

part是捕獲的變量,是每次迭代唯一的,因此每個表達式是唯一的。這種奇怪的行爲在設計上有所不同:請參閱a related question

編輯:它看起來像這正是什麼導致你的問題;最終查詢中的子查詢全部爲表格x <> y,這是添加到您的whereStatements集合中的最後一個查詢的形式。

+0

該死的,我再也不會忽視我的警告了。它在VS中被強調,但我忽略了它。我認爲範圍本來是一樣的。 非常感謝..第二組眼睛似乎已經解決了我的問題:) – TravisWhidden 2009-09-30 16:49:59