2010-03-17 81 views
0

我正在從ADO.NET轉移到Linq。該應用程序是一個目錄搜索程序,用於查看人員。用戶可以將搜索條件輸入到單個文本框中。他們可以用空格分隔每個術語,或者用引號括起「park place」等短語來表示它是一個術語。使用Linq搜索多項數據集

數據來自XML文件,其中有大約90,000條記錄,大約65 megs。我將數據加載到DataTable中,然後使用.Select方法和SQL查詢來執行搜索。我傳遞的查詢是根據用戶傳遞的搜索條件構建的。我使用正則表達式將文本框中的字符串拆分爲數組,該正則表達式將所有內容拆分爲一個單獨的元素,並在其中包含空格。但是,如果圍繞某個短語引用了引號,則該引號會變成數組中的自己的元素。然後我最終得到一個具有x個元素的單維數組,我重複構建一個長查詢。

我然後建立下面的搜索表達式:

 query = query & _ 
    "((userid LIKE '" & tempstr & "%') OR " & _ 
    "(nickname LIKE '" & tempstr & "%') OR " & _ 
    "(lastname LIKE '" & tempstr & "%') OR " & _ 
    "(firstname LIKE '" & tempstr & "%') OR " & _ 
    "(department LIKE '" & tempstr & "%') OR " & _ 
    "(telephoneNumber LIKE '" & tempstr & "%') OR " & _ 
    "(email LIKE '" & tempstr & "%') OR " & _ 
    "(Office LIKE '" & tempstr & "%'))" 

每個術語將具有一組以上的查詢。如果有多個術語,我在AND之間插入一個AND,然後在下一個術語中構建另一個類似於上面的查詢。我不知道如何在Linq中做到這一點。到目前爲止,我已經正確加載了XML文件。我可以用特定的標準搜索它,但我不確定如何最好地在多個術語上實現搜索。

'this works but far too simple to get the job done 
    Dim results = From c In m_DataSet...<Users> _ 
    Where c.<userid>.Value = "XXXX" _ 
    Select c  

上述代碼也不使用LIKE運算符。所以部分匹配不起作用。它看起來像我想要使用的是.Startswith,但似乎只在Linq2SQL。任何指導將不勝感激。我是Linq的新手,所以我可能會錯過一個簡單的方法來做到這一點。

的XML文件看起來像這樣:

<?xml version="1.0" standalone="yes"?> 
<theusers> 

<Users> 
<userid>person1</userid> 
<nickname></nickname> 
<lastname></lastname> 
<firstname></firstname> 
<department></department> 
<telephoneNumber></telephoneNumber> 
<email></email> 
</Users> 

<Users> 
<userid>person2</userid> 
<nickname></nickname> 
<lastname></lastname> 
<firstname></firstname> 
<department></department> 
<telephoneNumber></telephoneNumber> 
<email></email> 
</Users> 

######## ########更新 下面是VB完整可行的解決方案感謝我們的親切回答。


下面是該查詢你可以運行:

Dim query = From d In m_DataSet.Descendants("Users") _ 
       Where d.ChildrenBeginWith(rezsplit) _ 
       Select d  


這裏是擴展方法:

Public Module SearchEngine 
<System.Runtime.CompilerServices.Extension()> _ 
Public Function ChildrenBeginWith(ByVal parent As XElement, _ 
    ByVal ParamArray  searchTerms As String()) As Boolean 
    Dim ret As Boolean = False 
     Dim children = parent.Elements().ToList() 
     For Each searchTerm In searchTerms 
      ret = children.Any(Function(x) x.Value.StartsWith(searchTerm)) 
      If Not ret Then 
       Exit For 
      End If 
     Next 
     Return ret 
    End Function 
End Module 

回答

1

如果你只是想要的東西,使用LINQ到XML的工作你可以將您的xml加載到XDocument中並執行以下查詢。它將包含以指定文本開頭的任何子節點值。

Dim doc = XDocument.Parse("this is where your xml string goes") 
Dim query = From d In doc.Descendants("Users") _ 
      Where d.Elements().Any(Function(x As XElement) x.Value.StartsWith(tempStr)) _ 
      Select d 
For Each A In query 
    //Do Something 
Next 

編輯:對不起我不是一個VB的傢伙,所以下面的示例是C#(我本來寫了我的第一個答案在C#中,但它是很容易讓我轉換成VB)。我不知道土生土長乾淨地做你想做的,所以最簡單的方法可能是一個輔助方法或擴展方法如下所示:

新查詢:

var query = from d in doc.Descendants("Users") 
      where d.ChildrenBeginWith(tempStr, tempStr2) 
      select d; 

擴展方法:

public static class Extension 
{ 
    public static bool ChildrenBeginWith(this XElement parent, params string[] searchTerms) 
    { 
     bool ret = false; 
     var children = parent.Elements().ToList(); 
     foreach (var searchTerm in searchTerms) 
     { 
      ret = children.Any(x => x.Value.StartsWith(searchTerm)); 
      if (!ret) 
       break; 
     } 
     return ret; 
    } 
} 
+0

哇,那太棒了。這大大簡化了我腦海中的東西。我想唯一需要弄清的是多個術語。如果我只有一個搜索字詞,那麼您的解決方案是完美的。我需要處理多個。因此,如果用戶通過鮑勃800-123-5555,那麼鮑勃應該擊中綽號,或名字和電話號碼將打到telephoneNumber。 – 2010-03-17 15:07:01

+0

好的。我認爲我更接近,如果我做的話Where d.Elements()。Any(Function(x As XElement)x.Value.StartsWith(tempStr))AND _ Where d.Elements()。Any(Function(x As XElement )x.Value.StartsWith(tempStr2)) 它使我朝着正確的方向前進。你知道一種方法可以乾淨地做X的條款嗎? – 2010-03-17 15:19:41

+0

我不知道一個乾淨的方式來做本地你想做的事情,所以我寫了一個擴展方法的快速示例來幫助你(抱歉,它是在C#中,但希望它仍然可以幫助你)。 – 2010-03-17 15:58:07