Bagaimana melakukan SQL Like% di Linq?

385

Saya memiliki prosedur dalam SQL yang saya coba ubah menjadi Linq:

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

Garis yang paling saya perhatikan adalah:

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

Saya memiliki kolom yang menyimpan hierarki seperti / 1/3/12 / misalnya jadi saya hanya menggunakan% / 12 /% untuk mencarinya.

Pertanyaan saya adalah, apa yang setara dengan Linq atau .NET dengan menggunakan tanda persen?

Matt Dell
sumber
1
Pertanyaan Anda setidaknya memiliki 5suara untuk tag seperti operator . Bisakah saya meminta agar Anda menyarankan seperti sql sebagai sinonim ?
Kermit

Jawaban:

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

Anda juga dapat menggunakan .StartsWith()atau .EndsWith().

andleer
sumber
4
Apakah menggunakan StartsWith () atau EndsWith () akan memunculkan kueri? Maksud saya, akankah kode diterjemahkan ke dalam Query atau hasilnya akan disaring dalam objek setelah pengambilan dari DB?
Pemula
5
Tidak. StartsWith () dan EndsWith () adalah bagian dari predikat / filter. Eksekusi terus ditunda.
andleer
2
mencoba yang mendapat NullReferenceException: Referensi objek tidak disetel ke instance objek. Jadi tidak suka kalau dalam kasus saya a.Address1.StartsWith (Address1) dan a.Address1 adalah null
MikeT
11
StartsWith("abc")akan dikonversi menjadi LIKE 'abc%'dan EndsWith("abc")adalah cnoverted keLIKE '%abc'
Simon_Weaver
20
Tidak dapat menemukan alasan mengapa ini tidak berfungsi untuk kasus penggunaan dengan huruf, lalu menyadari kebodohan saya ... jangan lupa .ToLower().Contains()dll jika Anda ingin mengabaikan kasing. Apakah Anda ingin ini tentu saja tergantung pada apakah Anda mencoba untuk meniru LIKE dari DB dengan susunan case-case yang tidak sensitif atau tidak.
Adam Knights
251

Gunakan ini:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;
LP
sumber
22
ini sangat membantu jika Anda ingin menggunakan pencocokan pola yang lebih rumit yang disediakan oleh perintah like. Misalnya, jika Anda ingin memeriksa dua angka (bukan 12), Anda dapat menggunakan ungkapan ini: SqlMethods.Like (c.Hierarchy, "% / [0-9] [0-9] /%") Juga , lihat ini msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity
ini juga sangat berguna jika Anda ingin mengizinkan pengguna listrik untuk melakukan pra-pend% awal mahal sendiri, di mana menggunakan StartsWith atau Contains tidak memberikan fleksibilitas kepada pengguna daya ini
Simon_Weaver
8
Bagaimana Anda SqlMethodsmenggunakan "notasi titik"?
dan-gph
12
Perhatikan bahwa Anda harus menyertakan System.Data.Linq.SqlClientnamespace.
johna
1
Saya tidak dapat menemukan System.Data.Linq.SqlClient walaupun saya dapat menambahkan System.Data.Linq. Apakah sudah usang?
Burak Karakuş
41

Saya berasumsi Anda menggunakan Linq-to-SQL * (lihat catatan di bawah). Jika demikian, gunakan string.Contains, string.StartsWith, dan string.EndsWith untuk menghasilkan SQL yang menggunakan operator 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 }

atau

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

Catatan: * = jika Anda menggunakan ADO.Net Entity Framework (EF / L2E) di .net 3.5, perlu diketahui bahwa ia tidak akan melakukan terjemahan yang sama dengan Linq-to-SQL. Meskipun L2S melakukan terjemahan yang tepat, L2E v1 (3.5) akan menerjemahkan ke dalam ekspresi t-sql yang akan memaksa pemindaian tabel penuh pada tabel yang Anda query kecuali ada pembeda lain yang lebih baik di mana klausa Anda atau filter bergabung.
Pembaruan: Ini diperbaiki di EF / L2E v4 (.net 4.0), sehingga akan menghasilkan SEPERTI SQL seperti halnya L2S.

KristoferA
sumber
Tidak perlu melepaskan diri dari ikatan Anda dengan @tanda tetapi saya menyadari ini mungkin hanya konvensi yang baik untuk diikuti.
andleer
27

Jika Anda menggunakan VB.NET, maka jawabannya adalah "*". Berikut adalah di mana klausa Anda akan terlihat seperti ...

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

Catatan: "*" Cocok dengan nol atau lebih karakter. Ini adalah artikel msdn untuk operator Suka .

robertz
sumber
Apakah operator Suka VB menerjemahkan ke dalam panggilan L2S? (Saya tidak tahu.)
andleer
8
Ya, operator Suka VB akan diterjemahkan ke versi SQL like ketika digunakan dalam ekspresi kueri LINQ. Juga, operator Suka VB tidak terbatas pada ekspresi kueri.
robertz
1
Saya melihat bahwa itu ada di luar operasi LINQ. Barang bagus. +1
andleer
9

Yah indexOf bekerja untuk saya juga

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;
Rumplin
sumber
1
Ini harus menjadi jawaban yang diterima. IndexOf diterjemahkan ke CHARINDEX dalam sql. Ini mungkin lebih cepat daripada LIKE. Namun terlepas dari itu, ini memberikan kemungkinan untuk membuat permintaan pencarian seperti '% some% thing%'. Di mana 'beberapa' harus ditempatkan sebelum 'hal', yang tidak dapat dilakukan dengan Berisi.
Ruard van Elburg
Saya suka ketika jawaban yang saya butuhkan adalah 8 tahun dan menyelipkan beberapa tingkatan di bawah jawaban yang diterima. Sederhananya, ini berhasil sedangkan .Berisi (@ "/ 12 /") dan jawaban serupa lainnya tidak. Sangat dihargai!
IdusOrtus
4

Gunakan kode seperti itu

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;
}
Ernesto
sumber
4

Inti NET sekarang EF.Functions.Like

kofifus
sumber
Bisakah Anda menjelaskan cara menggunakan ini untuk menyelesaikan masalah OP?
Robert Columbia
lihat yaitu jawaban dari LP, itu hanya versi inti dari SqlMethods.Seperti
kofifus
Jawaban ini harus berisi contoh yang bisa ditindaklanjuti tentang cara menggunakan fungsi ini.
FoxDeploy
3

Jika Anda tidak cocok dengan string numerik, selalu baik untuk memiliki kasus umum:

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))
Masuk
sumber
2

Saya selalu melakukan ini:

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

Saya tahu saya tidak menggunakan pernyataan like tetapi berfungsi dengan baik di latar belakang apakah ini diterjemahkan ke dalam kueri dengan pernyataan like.

H. Pauwelyn
sumber
Bagaimana jawaban Anda berbeda dari jawaban yang diterima (dijawab 7 tahun yang lalu) atau jawaban lainnya? Nilai apa yang ditambahkannya?
David Ferenczy Rogožan
1
@DawidFerenczy Jawaban ini berfungsi dengan sintaks kueri "from foo in bar", dan yang diterima tidak.
nasch
1

Coba ini, ini berfungsi baik untuk saya

from record in context.Organization where record.Hierarchy.Contains(12) select record;
isuruAb
sumber
1
System.Data.Linq.SqlClient.SqlMethods.Like("mystring", "%string")
Tan Silliksaar
sumber
0

Berisi digunakan dalam Linq, Sama seperti Suka digunakan dalam SQL.

string _search="/12/";

. . .

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

Anda dapat menulis skrip SQL di Linq sebagai berikut:

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

Bagi mereka yang tumbang di sini seperti saya mencari cara untuk metode "Seperti SQL" di LINQ, saya memiliki sesuatu yang berfungsi dengan sangat baik.

Saya dalam kasus di mana saya tidak dapat mengubah Database dengan cara apa pun untuk mengubah susunan kolom. Jadi saya sudah menemukan cara di LINQ saya untuk melakukannya.

Saya menggunakan metode pembantu SqlFunctions.PatIndextindakan penyihir mirip dengan operator SEPERTI SQL nyata.

Pertama, saya perlu menghitung semua diakritik yang mungkin (kata yang baru saya pelajari) dalam nilai pencarian untuk mendapatkan sesuatu seperti:

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

dan kemudian di LINQ untuk contoh:

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();

Jadi untuk kebutuhan saya, saya telah menulis metode 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;
        }
    }

Jika ada di antara Anda yang memiliki saran untuk meningkatkan metode ini, saya akan senang mendengarkan Anda.

Hugo
sumber
Contoh Anda pada dasarnya adalah aksen tidak sensitif aksen homebrew. Saya pernah harus berurusan dengan proyek di mana setiap pertanyaan melewati filter untuk mencapai apa yang seharusnya dilakukan pemeriksaan otomatis. Silakan lihat stackoverflow.com/a/2461550/1736944 untuk apa yang biasanya merupakan pendekatan yang lebih baik. Tetapkan susunan yang tepat untuk basis data, tabel dan / atau bidang yang dianggap tepat. (Bekerja tanpa pemeriksaan yang layak di tempat adalah penyiksaan murni)
9Rune5
0

Jauh terlambat, tapi saya melemparkan ini bersama untuk bisa melakukan perbandingan String menggunakan wildcard gaya Suka 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;
    }
}
Steven Ackerman
sumber