Как сделать SQL Like% в Linq?


385

У меня есть процедура в SQL, которую я пытаюсь превратить в Linq:

SELECT O.Id, O.Name as Organization
FROM Organizations O
JOIN OrganizationsHierarchy OH ON O.Id=OH.OrganizationsId
where OH.Hierarchy like '%/12/%'

Линия, которая меня больше всего волнует:

where OH.Hierarchy like '%/12/%'

У меня есть столбец, в котором хранится иерархия, например / 1/3/12 /, поэтому я просто использую% / 12 /% для ее поиска.

Мой вопрос: что такое Linq или .NET эквивалентно использованию знака процента?


1
Ваш вопрос имеет по крайней мере 5голоса для тега like-operator . Могу ли я попросить вас предложить sql-like как синоним ?
— Кермит,

Ответы:


550
.Where(oh => oh.Hierarchy.Contains("/12/"))

Вы также можете использовать .StartsWith()или .EndsWith().


4
Будет ли использование StartsWith () или EndsWith () запускать запрос? Я имею в виду, будет ли код переведен в Запрос или результаты будут отфильтрованы в объекте после извлечения из БД?
— Новичок

5
Нет. StartsWith () и EndsWith () являются частью предиката / фильтра. Выполнение продолжает откладываться.
— andleer

2
попытался получить NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта. Поэтому ему не нравится, когда в моем случае a.Address1.StartsWith (Address1) и a.Address1 имеет значение null
— MikeT

11
StartsWith("abc")превращается в LIKE 'abc%'и EndsWith("abc")превращается вLIKE '%abc'
— Simon_Weaver

20
Не мог понять, почему это не сработало для сценария использования с буквами, затем понял мою глупость ... не забывайте и .ToLower().Contains()т. Д., Если хотите игнорировать регистр. То, хотите ли вы этого, будет, конечно, зависеть от того, пытаетесь ли вы подражать LIKE из БД с учетом сортировки без учета регистра или нет.
— Адам Найтс

251

Использовать этот:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;

22
это действительно полезно, если вы хотите использовать более сложное сопоставление с шаблоном, предоставляемое командой like. Например, если вы хотите проверить любые два числа (вместо 12), вы можете использовать это выражение: SqlMethods.Like (c.Hierarchy, "% / [0-9] [0-9] /%"). см. это msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
— viggity

это также очень полезно, если вы хотите, чтобы опытные пользователи сами предварительно ожидали дорогой начальный%, тогда как использование StartsWith или Contains не дает
— опытному

8
Как вы используете, SqlMethodsиспользуя «точечную нотацию»?
— Дан-г-н

12
Обратите внимание, что вам нужно включить System.Data.Linq.SqlClientпространство имен.
— Джон

1
Я не смог найти System.Data.Linq.SqlClient, хотя могу добавить System.Data.Linq. Это устарело?
— Бурак Каракуш

41

Я предполагаю, что вы используете Linq-to-SQL * (см. Примечание ниже). Если это так, используйте string.Contains, string.StartsWith и string.EndsWith для генерации SQL, в котором используется оператор SQL LIKE.

from o in dc.Organization
join oh in dc.OrganizationsHierarchy on o.Id equals oh.OrganizationsId
where oh.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

или

from o in dc.Organization
where o.OrganizationsHierarchy.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

Примечание: * = если вы используете ADO.Net Entity Framework (EF / L2E) в .net 3.5, учтите, что он не будет выполнять тот же перевод, что и Linq-to-SQL. Хотя L2S выполняет правильный перевод, L2E v1 (3.5) преобразуется в выражение t-sql, которое будет вызывать полное сканирование таблицы в запрашиваемой вами таблице, если только в вашем предложении where или фильтрах соединения нет другого лучшего дискриминатора.
Обновление: это исправлено в EF / L2E v4 (.net 4.0), поэтому он генерирует SQL LIKE, как и L2S.


Не нужно прятать свои строки со @знаком, но я понимаю, что это может быть хорошим соглашением.
— andleer

27

Если вы используете VB.NET, то ответ будет "*". Вот как бы выглядела статья where ...

Where OH.Hierarchy Like '*/12/*'

Примечание: "*" Соответствует нулю или более символов. Вот статья msdn для оператора Like .


Переводит ли оператор VB Like в вызовы L2S? (
— Понятия

8
Да, оператор VB Like переводится в SQL-версию like при использовании в выражении запроса LINQ. Кроме того, оператор VB Like не ограничивается выражениями запросов.
— Робертц

1
Я видел, что он существует вне операций LINQ. Хорошая вещь. +1
— andleer

9

Ну у меня тоже indexOf работает

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;

1
Это должен быть принятый ответ. IndexOf переводится в CHARINDEX в sql. Это может быть быстрее, чем как. Но кроме этого, это дает возможность создавать поисковые запросы, такие как «% some% thing%». Где «некоторые» должны быть расположены перед «вещью», чего нельзя сделать с помощью Contains.
— Рюард ван Элбург

Мне нравится, когда мне нужны ответы на 8 лет, и они спрятаны на несколько уровней ниже принятого ответа. Проще говоря, это сработало, тогда как .Contains (@ "/ 12 /") и другие подобные ответы - нет. Очень признателен!
— IdusOrtus

4

Используйте такой код

try
{
    using (DatosDataContext dtc = new DatosDataContext())
    {
        var query = from pe in dtc.Personal_Hgo
                    where SqlMethods.Like(pe.nombre, "%" + txtNombre.Text + "%")
                    select new
                    {
                        pe.numero
                        ,
                        pe.nombre
                    };
        dgvDatos.DataSource = query.ToList();
    }
}
catch (Exception ex)
{
    string mensaje = ex.Message;
}

4

.NET ядро ​​теперь имеет EF.Functions.Like


Можете ли вы объяснить, как использовать это для решения проблемы ОП?
— Роберт Колумбия,

см. то есть ответ от LP, это просто базовая версия SqlMethods.Like
— kofifus

Этот ответ должен содержать практический пример использования этой функции.
— FoxDeploy

3

Если вы не соответствуете числовым строкам, всегда хорошо иметь общий случай:

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))

2

Я делаю всегда это:

from h in OH
where h.Hierarchy.Contains("/12/")
select h

Я знаю, что не использую оператор like, но он отлично работает в фоновом режиме - это переводится в запрос с оператором like.


Чем ваш ответ отличается от принятого ответа (отвеченного 7 лет назад) или других ответов? Какую ценность это добавляет?
— Дэвид Ференци Рогожан,

1
@DawidFerenczy Этот ответ работает с синтаксисом запроса «from foo in bar», а принятый - нет.
— нащий

1

Попробуй это, у меня нормально работает

from record in context.Organization where record.Hierarchy.Contains(12) select record;


0

Contains используется в Linq, также как Like используется в SQL.

string _search="/12/";

, , ,

.Where(s => s.Hierarchy.Contains(_search))

Вы можете написать свой SQL-скрипт в Linq следующим образом:

 var result= Organizations.Join(OrganizationsHierarchy.Where(s=>s.Hierarchy.Contains("/12/")),s=>s.Id,s=>s.OrganizationsId,(org,orgH)=>new {org,orgH});

0

Для тех, кто здесь, вроде меня, ищет способ «SQL Like» в LINQ, у меня есть кое-что, что работает очень хорошо.

Я нахожусь в случае, когда я не могу каким-либо образом изменить базу данных, чтобы изменить параметры сортировки столбцов. Так что я должен найти способ в моем LINQ сделать это.

Я использую вспомогательный метод, который SqlFunctions.PatIndexдействует аналогично реальному оператору SQL LIKE.

Сначала мне нужно перечислить все возможные диакритические знаки (слово, которое я только что выучил) в поисковом значении, чтобы получить что-то вроде:

déjà     => d[éèêëeÉÈÊËE]j[aàâäAÀÂÄ]
montreal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l
montréal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l

а затем в LINQ для примера:

var city = "montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l";
var data = (from loc in _context.Locations
                     where SqlFunctions.PatIndex(city, loc.City) > 0
                     select loc.City).ToList();

Поэтому для своих нужд я написал метод Helper / Extension

   public static class SqlServerHelper
    {

        private static readonly List<KeyValuePair<string, string>> Diacritics = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("A", "aàâäAÀÂÄ"),
            new KeyValuePair<string, string>("E", "éèêëeÉÈÊËE"),
            new KeyValuePair<string, string>("U", "uûüùUÛÜÙ"),
            new KeyValuePair<string, string>("C", "cçCÇ"),
            new KeyValuePair<string, string>("I", "iîïIÎÏ"),
            new KeyValuePair<string, string>("O", "ôöÔÖ"),
            new KeyValuePair<string, string>("Y", "YŸÝýyÿ")
        };

        public static string EnumarateDiacritics(this string stringToDiatritics)
        {
            if (string.IsNullOrEmpty(stringToDiatritics.Trim()))
                return stringToDiatritics;

            var diacriticChecked = string.Empty;

            foreach (var c in stringToDiatritics.ToCharArray())
            {
                var diac = Diacritics.FirstOrDefault(o => o.Value.ToCharArray().Contains(c));
                if (string.IsNullOrEmpty(diac.Key))
                    continue;

                //Prevent from doing same letter/Diacritic more than one time
                if (diacriticChecked.Contains(diac.Key))
                    continue;

                diacriticChecked += diac.Key;

                stringToDiatritics = stringToDiatritics.Replace(c.ToString(), "[" + diac.Value + "]");
            }

            stringToDiatritics = "%" + stringToDiatritics + "%";
            return stringToDiatritics;
        }
    }

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


Ваш пример - это в основном невосприимчивая сортировка домашнего приготовления. Когда-то мне приходилось иметь дело с проектом, в котором каждый запрос проходил через фильтр, чтобы добиться того, что бы правильная сортировка делалась автоматически. Пожалуйста, см. Stackoverflow.com/a/2461550/1736944 для того, что обычно является лучшим подходом. Присвойте правильное сопоставление базе данных, таблице и / или полю, если считаете это необходимым. (Работа без правильного сопоставления на месте - это чистая пытка)
— 9Rune5

0

Поздно, но я собрал это вместе, чтобы можно было проводить сравнения строк с использованием подстановочных знаков в стиле SQL Like:

public static class StringLikeExtensions
{
    /// <summary>
    /// Tests a string to be Like another string containing SQL Like style wildcards
    /// </summary>
    /// <param name="value">string to be searched</param>
    /// <param name="searchString">the search string containing wildcards</param>
    /// <returns>value.Like(searchString)</returns>
    /// <example>value.Like("a")</example>
    /// <example>value.Like("a%")</example>
    /// <example>value.Like("%b")</example>
    /// <example>value.Like("a%b")</example>
    /// <example>value.Like("a%b%c")</example>
    /// <remarks>base author -- Ruard van Elburg from StackOverflow, modifications by dvn</remarks>
    /// <remarks>converted to a String extension by sja</remarks>
    /// <seealso cref="/programming/1040380/wildcard-search-for-linq"/>
    public static bool Like(this String value, string searchString)
    {
        bool result = false;

        var likeParts = searchString.Split(new char[] { '%' });

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = value.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = value.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= value.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = value.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = value.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }

    /// <summary>
    /// Tests a string containing SQL Like style wildcards to be ReverseLike another string 
    /// </summary>
    /// <param name="value">search string containing wildcards</param>
    /// <param name="compareString">string to be compared</param>
    /// <returns>value.ReverseLike(compareString)</returns>
    /// <example>value.ReverseLike("a")</example>
    /// <example>value.ReverseLike("abc")</example>
    /// <example>value.ReverseLike("ab")</example>
    /// <example>value.ReverseLike("axb")</example>
    /// <example>value.ReverseLike("axbyc")</example>
    /// <remarks>reversed logic of Like String extension</remarks>
    public static bool ReverseLike(this String value, string compareString)
    {
        bool result = false;

        var likeParts = value.Split(new char[] {'%'});

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = compareString.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = compareString.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= compareString.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = compareString.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = compareString.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.