使用Linq搜索具有多个术语的一组数据

时间:2010-03-17 14:08:06

标签: vb.net ado.net linq-to-xml

我正在从ADO.NET迁移到Linq。该应用程序是一个目录搜索程序,以查找人。允许用户在单个文本框中键入搜索条件。他们可以用空格分隔每个术语,或者在引号中包含一个短语,例如“park place”,表示它是一个术语。

在幕后,数据来自一个XML文件,其中包含大约90,000条记录,大约为65兆。我将数据加载到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,并在下一个术语中构建另一个如上所述的查询。我不确定如何在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 个答案:

答案 0 :(得分:1)

如果您只想要与linq-to-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;
    }
}