Частичный поиск в Linq для пробела отдельных значений

1

У меня есть поле "Название", и вы хотите частично искать данные, введенные пользователем, которые могут быть разделены пробелами. Скажем, что пользователь вводит "ABC India PVT Ltd", запрос должен искать все записи, содержащие какие-либо одно или несколько введенных слов. как в sql, это было бы

Select * 
from Company 
where CompanyName like '%ABC%' or 
      CompanyName like '%India%' or 
      CompanyName like '%PVT%' or 
      CompanyName like '%Ltd%'

Я пытаюсь сделать что-то подобное

string search = "ABC India PVT Ltd"
String[] searchArray = search.Split(' ');
IEnumerable<Account> accountInfo = acctInfo.Get(Filter: a
=>searchArray.AsQueryable().Contains(a.CompanyName));

но это дает мне точно противоположность тому, чего я пытаюсь достичь. Есть ли способ, которым я могу это достичь.

Основная идея заключается в подстановочном поиске, в поле companyname для любого из значений searchArray.

a.CompanyName.Contains("Любое значение из searchArray")

Теги:
linq
entity-framework

2 ответа

1
Лучший ответ

Это делает трюк. Использовать Any() для фильтрации записей, содержащих одно из ключевых слов:

string searchTerm = "ABC India PVT Ltd";
string[] keywords = searchTerm.Split(' ');

List<Records> records = new List<Records>();
records.Add(new Records() { CompanyName = "Foo name" });
records.Add(new Records() { CompanyName = "ABC name" });
records.Add(new Records() { CompanyName = "Foo India" });
records.Add(new Records() { CompanyName = "PVT name" });
records.Add(new Records() { CompanyName = "Foo name" });
records.Add(new Records() { CompanyName = "Foobar" });
records.Add(new Records() { CompanyName = "Stackoverflow" });

var results = records.Where(x => keywords.Any(keyword => x.CompanyName
                                         .Contains(keyword))).ToList();

Класс манекена:

public class Records
{
    public Records() { }
    public string CompanyName { get; set; }
}

Дам вам List<Record> записей которого CompanyName содержит любые из ключевых слов. Например

  • "ABC name"
  • "Foo India"
  • "PVT name"
1

Решение с Any предложенное DGibbs, подходит для небольшого количества элементов (что, вероятно, будет иметь место для вас, так что я его поддержал), но EF не может создать эффективный запрос из этой конструкции. Вот как выглядит запрос с 4 элементами:

SELECT 
-- some fields
FROM [dbo].[Company] AS [Extent1]
WHERE  EXISTS (SELECT 
    1 AS [C1]
    FROM  (SELECT 
        [UnionAll2].[C1] AS [C1]
        FROM  (SELECT 
            [UnionAll1].[C1] AS [C1]
            FROM  (SELECT 
                N'a' AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
            UNION ALL
                SELECT 
                N'b' AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
        UNION ALL
            SELECT 
            N'c' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
    UNION ALL
        SELECT 
        N'd' AS [C1]
        FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3]
    WHERE ( CAST(CHARINDEX([UnionAll3].[C1], [Extent1].[Name]) AS int)) > 0
)

Это не масштабируемо. Помимо определенного количества элементов (только десятки) запрос будет генерировать исключение SQL, в котором был превышен максимальный уровень вложенности.

Чтобы предотвратить это, вы должны создать запрос с предложениями OR. Здесь PredicateBuilder поможет:

var predicate = PredicateBuilder.False<Company>();

foreach (var keyword in searchArray)
{
    predicate = predicate.Or(c => c.Name.Contains(keyword));
}

var query = Companies.Where(predicate.Expand());

Есть, кстати, альтернатива исходному коду LINQKit PredicateBuilder, которая делает то же самое, но без Expand.

  • 0
    Большое спасибо за ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню