Як зробити 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голосів за тег " оператор" . Чи можу я просити Вас , що ви пропонуєте SQL-подібний як синонім ?
Керміт

Відповіді:


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

Ви також можете використовувати .StartsWith()або .EndsWith().


4
Чи запустить запит запуску за допомогою StartsWith () або EndsWith ()? Я маю на увазі, чи буде переведений код у Запит чи результати будуть відфільтровані в об’єкті після отримання з БД?
Новичок

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

2
спробував отримати NullReferenceException: Посилання на об'єкт не встановлено для екземпляра об'єкта. Тому це не подобається, коли в моєму випадку a.Address1.StartsWith (Address1) та a.Address1 є нульовим
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
це дуже корисно, якщо ви хочете скористатися складнішим узгодженням шаблону, передбаченим подібною командою. Наприклад, якщо ви хочете перевірити наявність будь-яких двох чисел (замість 12), ви можете використовувати цей вираз: SqlMethods.Like (c.Hierarchy, "% / [0-9] [0-9] /%") Також , дивіться це msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity

це також дуже корисно, якщо ви хочете дозволити користувачам живлення самостійно попередньо відкласти дорогий початковий%, коли використання StartsWith або Contains не дає користувачеві цієї гнучкості гнучкості
Simon_Weaver

8
Як ви використовуєте SqlMethods"нотацію точок"?
дан-gph

12
Зауважте, що вам потрібно включити System.Data.Linq.SqlClientпростір імен.
johna

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-SQL. Хоча L2S робить належний переклад, L2E v1 (3.5) перетвориться на вираз t-sql, який змусить сканувати повну таблицю на таблиці, яку ви запитуєте, якщо немає іншого кращого дискримінатора у ваших фільтрах для клавіш або приєднання.
Оновлення: це виправлено в EF / L2E v4 (.net 4.0), тож він генерує SQL LIKE так само, як це робить L2S.


Не потрібно уникати своїх рядків зі @знаком, але я розумію, що це може бути лише хорошою умовою, яку слід дотримуватися.
andleer

27

Якщо ви використовуєте VB.NET, то відповідь буде "*". Ось як виглядатиме ваш пункт де…

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

Примітка: "*" Відповідає нулю або більше символів. Ось стаття msdn для оператора Like .


Чи переводить оператор VB Like в L2S-дзвінки? (Я не маю уявлення.)
andleer

8
Так, оператор VB Like отримує переклад на версію SQL як, коли використовується у виразі запиту LINQ. Також оператор VB Like не обмежується запитами виразів.
robertz

1
Я бачив, що він існує поза операціями LINQ. Хороший матеріал. +1
andleer

9

Ну і indexOf працює і для мене

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

1
Це має бути прийнятою відповіддю. IndexOf перекладається на CHARINDEX у sql. Це може бути швидше, ніж LIKE. Але крім цього, це дає можливість конструювати пошукові запити типу "% деякий% річ%". Де "деякі" повинні бути розташовані перед "річчю", що неможливо зробити із "Містить".
Руард ван Ельбург

Мені подобається, коли мені потрібні відповіді віком 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

Я знаю, що я не використовую подібний оператор, але це добре працює на задньому плані - це це переклад на запит із подібним висловом.


Чим ваша відповідь відрізняється від прийнятої відповіді (відповіли 7 років тому) чи інших відповідей? Яке значення вона додає?
Девід Ференці Рогожан

1
@DawidFerenczy Ця відповідь працює із синтаксисом запиту "від foo in bar", а прийнятий - ні.
нащ

1

Спробуйте це, мені це добре працює

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


0

Міститься використовується в 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:

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.