Как сделать 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().

andleer
источник
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 *;
LP
источник
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 .

robertz
источник
Переводит ли оператор 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;
Rumplin
источник
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

kofifus
источник
Можете ли вы объяснить, как использовать это для решения проблемы ОП?
Роберт Колумбия,
см. то есть ответ от 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.

H. Pauwelyn
источник
Чем ваш ответ отличается от принятого ответа (отвеченного 7 лет назад) или других ответов? Какую ценность это добавляет?
Дэвид Ференци Рогожан,
1
@DawidFerenczy Этот ответ работает с синтаксисом запроса «from foo in bar», а принятый - нет.
нащий
1

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

from record in context.Organization where record.Hierarchy.Contains(12) select record;
isuruAb
источник
1
System.Data.Linq.SqlClient.SqlMethods.Like("mystring", "%string")
Тан Силликсаар
источник
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});
UJS
источник
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;
    }
}
Стивен Акерман
источник