2010-12-14 48 views
1

我很難將一個複雜的sql查詢重寫爲linq。非常複雜的linq

-- gets the SpecificationAttributeOptionIDs that are in the FilteredSpecs list, but don't match 
    SELECT * FROM #FilteredSpecs [fs] 
          WHERE [fs].SpecificationAttributeOptionID NOT IN 
          ( 
           -- gets the SpecificationAttributeOptionIDs that match 
           SELECT psam.SpecificationAttributeOptionID 
           FROM dbo.Nop_Product_SpecificationAttribute_Mapping psam 
           WHERE psam.AllowFiltering = 1 AND psam.ProductID = 1 
          ) 

基本上我有什麼,是一個名單FilteredSpec這是C#是一個int列表。我試圖從FilteredSpec列表中獲取所有包含所有屬性選項的產品。

我已經試過這是(這給我有限的LINQ的知識顯然是行不通的):

var query = from p in Products 
         where (p.NpProductSpecificationAttributes.Select(a => filters.Contains(a.NpSpecificationAttributeOption.SpecificationAttributeOptionId)).Count() == 0) 
         select p; 

任何人都可以指導我在正確的方向嗎?

回答

2

這可能是最簡單的:

var query = Products.Where(
    p => FilteredSpec.All(
     fs => p.NpProductSpecificationAttributes.Any(
      a => a.NpSpecificationAttributeOption.AllowFiltering && 
       a.NpSpecificationAttributeOption.SpecificationAttributeOptionId == fs))); 

這是可能的LINQ到實體將不知道如何翻譯這個如果FilteredSpec實際上是一個List對象。如果是這樣的話,讓我知道,我們會看看我們是否可以想出其他解決方案。

+0

哇。謝謝。你是一個linq天才:))他們都工作,並認爲第二個是更快一點,清潔的SQL。我還沒有想出如何測試NpProductSpecificationAttribute是否將AllowFiltering屬性設置爲true – 2010-12-14 19:04:41

+0

我最終設法對該屬性進行了測試。雖然我更容易。感謝您的解決方案。你是最棒的! – 2010-12-14 19:14:46

+1

@Tudor Carean:我編輯了第二個答案來檢查AllowFiltering屬性,並擺脫了第一個答案(這會更復雜)。 – StriplingWarrior 2010-12-14 19:20:10

4

首先,不要使用Count(),除非您真的需要確切知道有多少元素。使用Count()來測試空集可能需要遍歷整個數據集。當您的數據集大小超過少數項目時,這對性能至關重要。使用 ! .Any()代替.Count()== 0,.Any()代替.Count()> 0.

接下來,您在原始SQL中的NOT IN測試聽起來像是一組差異操作。在LINQ中,用.Except表示.Except()A.Except(B)返回A中未找到的所有元素B.

我對你的問題描述有點困惑。在文本中,您說您想要查找包含FilterSpec列表中找到的所有屬性選項的所有產品。但是在你的兩個代碼示例中,你都使用NOT IN或測試Contains返回一個空的結果,這似乎是在與文本描述相反的方向上運行。

如果您試圖查找所有具有FilterSpec列表中找到的所有屬性選項的產品,那麼您正在查找集合等價。

如果您的屬性選項和您的filterspec列表中的項目總是以特定順序列出,那麼您可以使用Linq的.SequenceEqual()函數。我假設你的屬性選項沒有排序,所以.SequenceEqual()不是正確的解決方案。

要測試兩組值A和B的等價性與順序無關,您可以測試A.Except(B)爲空且B.Except(A)爲空。使用 ! .Any()測試爲空。第一個說A中的所有東西都可以在B中找到,第二個說B中的所有東西都可以在A中找到。還有什麼?沒什麼,所以這兩套必須包含完全相同的元素。

嘗試這樣的事情(未測試):

var query = from p in Products 
      where !p.NpProductSpecificationAttributes.Except(filters).Any() && 
        !filters.Except(p.NpProductSpecificationAttributes).Any() 
      select p; 

您可以通過使用一個HashSet可能會獲得更好的性能,如果僅僅是爲了減少時間hashsets的數量必須在內部通過上面的表達式來創建。下面的代碼假定過濾器列表和產品屬性中沒有重複的項目。如果您的SpecificationAttributeOptionId不是原始類型(string,int),那麼您可能還需要指定一個相等比較器。

var filterset = new HashSet<filteritemtype>(filters); 
    var query = from p in Products 
       where filterset.SetEquals(new HashSet<itemtype>(p.NpProductSpecificationAttributes)) 
       select p;