Вопрос по c#, sql, linq – Поиск по шаблону для LINQ

33

Я хотел бы знать, возможно ли выполнить поиск по шаблону с помощью LINQ.

Я вижу, что в LINQ есть Contains, StartsWith, EndsWith и т. Д.

Что, если я хочу что-то вроде% Test, если% it работает%, как мне это сделать?

С уважением

Ваш Ответ

12   ответов
2
.Where( column LIKE "Pattern")
Хорошо для VB, но не C #.
1

var myresult = db.MyItems.Where(x=>x.MyField.Contains(mysearchstring));
1

говорите ли вы на LinqToSql или просто на linq ... но вы можете использовать регулярные выражения:

.Where(dto => System.Text.RegularExpressions.Regex.IsMatch(dto.CustomerName, @"Ad"));
2
var result = (from x in db.Members
              where x.IDNumber.Contains(idnumber)
              && x.InstitutionIdentifier == institution.Identifier
              select x).ToList();
return result;

33

так как вы не всегда можете использовать Linq to SQL.

Как этот пример Linq to Objects

List<string> list = new List<string>();
list.Add("This is a sentence.");
list.Add("This is another one.");
list.Add("C# is fun.");
list.Add("Linq is also fun.");

System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex("This");

var qry = list
    .Where<string>(item => regEx.IsMatch(item))
    .ToList<string>();

// Print results
foreach (var item in qry)
{
    Console.WriteLine(item);
}
Вы всегда предполагаете, что вызываете базу данных SQL. Что делать, если вы запрашиваете список, который был создан в памяти?
Немного затянуто - он может просто использовать SqlMethods.Like
Давать общее решение для конкретной проблемы НЕ ПЛОХО.
Его вопрос помечен SQL
2

Я знаю, что это и старая тема, но вот мое очень простое решение:

string s=Regex.Escape("pattern - escaped for sanity").Replace("%", ".*").Replace("_", ".?");
user => Regex.IsMatch(user.FullName, s, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

В этом коде я использую общие escape-символы для языка SQL. Если вы хотите использовать, скажем* а также?экранированная строка будет содержать\* а также\? соответственно, обязательно включитеbackslash персонаж в.Replace(...) заявления). Конечно, если вы хотите дать своему пользователю возможность поиска RexEx, просто не экранируйте строку шаблона.

Поиск Regex учебник для других вариантов.

Я верю нормально% будет соответствоватьat least one characterв то время как RegEx.* будет соответствоватьzero or more персонажи. Так что на самом деле,% подстановочный знак больше похож.+ (жадный), а не.* (Ленивый).

Надеюсь это поможет.

3

What if I want something like %Test if%it work%, how do I do it?

тогда я ожидаю чего-то

LIKE '%Test if%it work%'

это означает, что строка должна содержать «Test if» и "это работает",in that order.

Это не будет работать:

context.SomeTable.Where(s => s.Name.Contains("Test if%it work")).ToList();

И если я использую:

context.SomeTable.Where(s => s.Name.Contains("Test if") && s.Name.Contains("it work")).ToList();

тогда я найду все записи, которые содержат как & quot; Test if & quot; и "это работает",but not specifically in that order.

Так сContains это невозможно. Но сIndexOf это.

IndexOf найдет строку поиска и вернет ее положение в строке. Позволяет найти слова в правильном порядке.

-- Обновить --

Исходя из моего первоначального ответа, я не ставил перед собой цель предоставить общее решение, а скорее стал примером другого подхода, который не зависит от SQL. Поэтому правильно, что оригинальный пример отвечает только на буквальный вопрос. Но так как ответ может быть более полезным, если он является общим, я написал расширение IQuerable, которое позволяет добавлять оператор запроса like в запрос так же просто, как оператор where. Расширение работает как для Linq, так и для Linq-Sql.

This will find all records with both "Test if" and "it work", in that order.

context.SomeTable.Like("test if%it work", "Name").ToList();

listOfString.Like("test if%it work").ToList();

Расширение, допускает любое количество подстановочных знаков:

/// <summary>
/// Allow to search the string with wildcards.
/// </summary>
/// <typeparam name="T">String or an object with a string member.</typeparam>
/// <param name="q">Original query</param>
/// <param name="searchstring">The searchstring</param>
/// <param name="memberName">The name of the field or null if not a field.</param>
/// <returns>Query filtered by 'LIKE'.</returns>
public static IQueryable<T> Like<T>(this IQueryable<T> q, string searchstring, string memberName = null)
{
    // %a%b%c% --> IndexOf(a) > -1 && IndexOf(b) > IndexOf(a) && IndexOf(c) > IndexOf(b)

    var eParam = Expression.Parameter(typeof(T), "e");

    MethodInfo methodInfo;

    // Linq (C#) is case sensitive, but sql isn't. Use StringComparison ignorecase for Linq.
    // Sql however doesn't know StringComparison, so try to determine the provider.
    var isLinq = (q.Provider.GetType().IsGenericType && q.Provider.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>));
    if (isLinq)
        methodInfo = typeof(string).GetMethod("IndexOf", ,new[] { typeof(string), typeof(StringComparison) });
    else
        methodInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });

    Expression expr;
    if (string.IsNullOrEmpty(memberName))
        expr = eParam;
    else
        expr = Expression.Property(eParam, memberName);

    // Split the searchstring by the wildcard symbol:
    var likeParts = searchstring.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries);

    for (int i = 0; i < likeParts.Length; i++)
    {
        MethodCallExpression e;
        if (isLinq)
            e = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
        else
            e = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i], typeof(string)));

        if (i == 0)
        {
            // e.IndexOf("likePart") > -1
            q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(e, Expression.Constant(-1, typeof(int))), eParam));
        }
        else
        {
            // e.IndexOf("likePart_previous")
            MethodCallExpression ePrevious;
            if (isLinq)
                ePrevious = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i - 1], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
            else
                ePrevious = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i - 1], typeof(string)));

            // e.IndexOf("likePart_previous") < e.IndexOf("likePart")
            q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.LessThan(ePrevious, e), eParam));
        }
    }
    return q;
}

Поскольку ему не нужны SqlMethods, я предполагаю, что вы можете использовать это для любой базы данных, например, MySql или Postgresql. Но я не знаю точно. Я проверил это на Sql Server, используя Entity Framework 6. Вышеуказанный оператор генерирует следующий код на Sql Server.

SELECT [Extent1].* FROM SomeTable AS [Extent1]
WHERE ((( CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) > -1)
AND ((( CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) < 
   ,  (( CAST(CHARINDEX(N'it work', [Extent1].[Name]) AS int)) - 1))

Что касается производительности, то, похоже, идет дискуссия о том, что лучше: LIKE или CHARINDEX. И из того, что я читал, CHARINDEX кажется любимым.

Ваш ответ не содержит ответа на общий вопрос о том, как реализовать поиск по шаблону в LINQ, он просто отвечает на конкретный пример и не будет работать ни при каких других обстоятельствах. Как таковой, он не дает полезного ответа на вопрос.
@ Frosty840 Я обновил ответ.
На самом деле я искал ответ, специфичный для SQL, так как меня раздражает необходимость писать дополнительный общий код, который мне никогда не понадобится, поскольку мы всегда будем использовать SQL Server. К сожалению, пока вы показали, почему содержимое не будет работать, вы не показали ничего более простого, чем было бы. Сравнение, которое я пытаюсь сделать, является одним из ряда содержит. Так что я надеялся добавить что-нибудь простое в эту строку. Похоже, SQLMethods.Like придется использовать.
0

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

1

IsSqlLikeMatch функция из потокаИспользование Regex для создания SQL, подобного & quot; как функция.

Пример использования

bool ret = message.IsSqlLikeMatch(pattern);

Подробнее в моем посте SQL & lt; s & quot; как & quot; шаблоны для сравнения в .Net

74

SqlMethods.Like ().

Пример использования:

var results =
        from u in users
        where SqlMethods.Like(u.FirstName, "%John%")
        select u;
очень круто! не знал, что существовало ...
Это будет работать только с запросами LinqToSql (как должно быть видно по используемому классу).
Очень хорошо, я не знал, что существовало +1
Вау, я никогда не знал, что есть класс SqlMethods.
14

а затем попробуйте:

var results= from x in data
             where SqlMethods.Like(x.SearchField, “%something%like%this%”)
             select x;
6

Entity Framework Core 2.0 естьLIKE оператор (объявлено в августе 2017 года):

var query = from e in _context.Employees
                    where EF.Functions.Like(e.Title, "%developer%")
                    select e;
Оно работает. Спасибо

Похожие вопросы