Поиск набора данных с несколькими терминами с использованием Linq - PullRequest
0 голосов
/ 17 марта 2010

Я в процессе перехода от ADO.NET к Linq. Приложение представляет собой программу поиска в каталоге, чтобы искать людей. Пользователи могут вводить критерии поиска в одном текстовом поле. Они могут разделять каждый термин пробелом или заключать фразу в кавычки, такие как «парковое место», чтобы указать, что это один термин.

За кулисами данные поступают из 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 Ответ

1 голос
/ 17 марта 2010

Если вам просто нужно что-то, что работает с 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...