Wie mache ich SQL Like% in Linq?

385

Ich habe eine Prozedur in SQL, die ich in Linq umwandeln möchte:

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

Die Linie, mit der ich mich am meisten beschäftige, ist:

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

Ich habe eine Spalte, in der die Hierarchie wie / 1/3/12 / gespeichert ist, also verwende ich nur% / 12 /%, um danach zu suchen.

Meine Frage ist, was entspricht Linq oder .NET der Verwendung des Prozentzeichens?

Matt Dell
quelle
1
Ihre Frage hat mindestens 5Stimmen für das Like-Operator- Tag. Könnte ich Sie bitten , SQL-like als Synonym vorzuschlagen ?
Kermit

Antworten:

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

Sie können auch .StartsWith()oder verwenden .EndsWith().

andleer
quelle
4
Wird bei Verwendung von StartsWith () oder EndsWith () eine Abfrage ausgelöst? Ich meine, wird der Code in eine Abfrage übersetzt oder werden die Ergebnisse nach dem Abrufen aus der Datenbank im Objekt gefiltert?
Anfänger
5
StartsWith () und EndsWith () sind Teil des Prädikats / Filters. Die Ausführung wird weiterhin verschoben.
andleer
2
versucht, dass NullReferenceException erhalten: Objektreferenz nicht auf eine Instanz eines Objekts gesetzt. Also mag es nicht, wenn in meinem Fall a.Address1.StartsWith (Address1) und a.Address1 null ist
MikeT
11
StartsWith("abc")wird umgewandelt in LIKE 'abc%'und EndsWith("abc")wird inLIKE '%abc'
Simon_Weaver
20
Konnte nicht herausfinden, warum dies für einen Anwendungsfall mit Buchstaben nicht funktionierte, und erkannte dann meine Dummheit ... vergiss .ToLower().Contains()usw. nicht, wenn du den Fall ignorieren willst. Ob Sie dies möchten, hängt natürlich davon ab, ob Sie versuchen, LIKE aus einer Datenbank mit einer Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung nachzuahmen oder nicht.
Adam Knights
251

Benutze das:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;
LP
quelle
22
Dies ist sehr hilfreich, wenn Sie den komplizierteren Mustervergleich verwenden möchten, der mit dem Befehl like bereitgestellt wird. Wenn Sie beispielsweise nach zwei beliebigen Zahlen (anstelle von 12) suchen möchten, können Sie diesen Ausdruck verwenden: SqlMethods.Like (c.Hierarchy, "% / [0-9] [0-9] /%") Also , siehe diese msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity
Dies ist auch sehr nützlich, wenn Sie Power-Usern erlauben möchten, den teuren Anfangsbuchstaben% selbst vorzuhängen, wenn die Verwendung von StartsWith oder Contains dem Power-User diese Flexibilität nicht
bietet
8
Wie benutzt man SqlMethodsdie "Punktnotation"?
Dan-Gph
12
Beachten Sie, dass Sie den System.Data.Linq.SqlClientNamespace einschließen müssen .
Johna
1
Ich konnte System.Data.Linq.SqlClient nicht finden, obwohl ich System.Data.Linq hinzufügen kann. Ist es veraltet?
Burak Karakuş
41

Ich gehe davon aus, dass Sie Linq-to-SQL * verwenden (siehe Hinweis unten). Verwenden Sie in diesem Fall string.Contains, string.StartsWith und string.EndsWith, um SQL zu generieren, das den SQL LIKE-Operator verwendet.

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 }

oder

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

Hinweis: * = Wenn Sie das ADO.Net Entity Framework (EF / L2E) in .net 3.5 verwenden, beachten Sie, dass es nicht dieselbe Übersetzung wie Linq-to-SQL ausführt. Obwohl L2S eine ordnungsgemäße Übersetzung ausführt, wird L2E v1 (3.5) in einen t-sql-Ausdruck übersetzt, der einen vollständigen Tabellenscan für die von Ihnen abgefragte Tabelle erzwingt, es sei denn, Ihre where-Klausel oder Join-Filter enthalten einen anderen besseren Diskriminator.
Update: Dies ist in EF / L2E v4 (.net 4.0) behoben, sodass genau wie bei L2S ein SQL LIKE generiert wird.

KristoferA
quelle
Sie müssen sich nicht mit dem @Zeichen entziehen , aber mir ist klar, dass dies möglicherweise nur eine gute Konvention ist.
andleer
27

Wenn Sie VB.NET verwenden, lautet die Antwort "*". So würde Ihre where-Klausel aussehen ...

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

Hinweis: "*" Entspricht null oder mehr Zeichen. Hier ist der msdn-Artikel für den Like-Operator .

robertz
quelle
Wird der VB Like-Operator in L2S-Aufrufe übersetzt? (Ich habe keine Ahnung.)
andleer
8
Ja, der VB Like-Operator wird in die SQL-Version von like übersetzt, wenn er in einem LINQ-Abfrageausdruck verwendet wird. Außerdem ist der VB Like-Operator nicht auf Abfrageausdrücke beschränkt.
Robertz
1
Ich habe gesehen, dass es außerhalb der LINQ-Operationen existiert. Gutes Zeug. +1
andleer
9

Nun, indexOf funktioniert auch bei mir

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;
Rumplin
quelle
1
Dies sollte die akzeptierte Antwort sein. IndexOf übersetzt in CHARINDEX in SQL. Dies kann möglicherweise schneller als LIKE sein. Abgesehen davon gibt es die Möglichkeit, Suchanfragen wie '% some% thing%' zu erstellen. Wo 'einige' vor 'Ding' stehen müssen, was mit Contains nicht möglich ist.
Ruard van Elburg
Ich liebe es, wenn die Antworten, die ich brauche, 8 Jahre alt sind und mehrere Ebenen unter der akzeptierten Antwort liegen. Einfach ausgedrückt funktionierte dies, während .Contains (@ "/ 12 /") und andere ähnliche Antworten dies nicht taten. Sehr geschätzt!
IdusOrtus
4

Verwenden Sie einen solchen Code

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
quelle
4

.NET Core hat jetzt EF.Functions.Like

Kofifus
quelle
Können Sie erklären, wie Sie damit das Problem des OP lösen können?
Robert Columbia
siehe zB die Antwort von LP, es ist nur die Kernversion von SqlMethods.Like
kofifus
Diese Antwort sollte ein umsetzbares Beispiel für die Verwendung dieser Funktion enthalten.
FoxDeploy
3

Wenn Sie nicht mit numerischen Zeichenfolgen übereinstimmen, ist es immer gut, einen allgemeinen Fall zu haben:

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))
Komm herein
quelle
2

Ich mache immer das:

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

Ich weiß, dass ich die like-Anweisung nicht verwende, aber im Hintergrund funktioniert sie einwandfrei. Dies wird in eine Abfrage mit einer like-Anweisung übersetzt.

H. Pauwelyn
quelle
Wie unterscheidet sich Ihre Antwort von der akzeptierten Antwort (vor 7 Jahren beantwortet) oder anderen Antworten? Welchen Wert bringt es?
David Ferenczy Rogožan
1
@DawidFerenczy Diese Antwort funktioniert mit der Abfragesyntax "from foo in bar" und die akzeptierte nicht.
Nasch
1

Versuchen Sie dies, das funktioniert gut für mich

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

Contains wird in Linq verwendet, genau wie Like in SQL.

string _search="/12/";

. . .

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

Sie können Ihr SQL-Skript in Linq wie folgt schreiben:

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

Für diejenigen, die hier wie ich nach einem Weg zu einer "SQL Like" -Methode in LINQ suchen, gibt es etwas, das sehr gut funktioniert.

Ich bin in einem Fall, in dem ich die Datenbank in keiner Weise ändern kann, um die Spaltenkollatierung zu ändern. Also muss ich in meinem LINQ einen Weg finden, dies zu tun.

Ich verwende die Hilfsmethode, SqlFunctions.PatIndexdie sich ähnlich wie der echte SQL LIKE-Operator verhält.

Zuerst muss ich alle möglichen diakritischen Zeichen (ein Wort, das ich gerade gelernt habe) im Suchwert aufzählen, um Folgendes zu erhalten:

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

und dann in LINQ zum Beispiel:

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

Für meine Bedürfnisse habe ich eine Helper / Extension-Methode geschrieben

   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;
        }
    }

Wenn einer von Ihnen Vorschläge zur Verbesserung dieser Methode hat, werde ich mich freuen, Sie zu hören.

Hugo
quelle
Ihr Beispiel ist im Grunde eine selbstgebraute, akzentunempfindliche Zusammenstellung. Ich musste mich einmal mit einem Projekt befassen, bei dem jede einzelne Abfrage einen Filter durchlief, um zu erreichen, was eine ordnungsgemäße Sortierung automatisch bewirkt hätte. Weitere Informationen zu einem normalerweise besseren Ansatz finden Sie unter stackoverflow.com/a/2461550/1736944 . Weisen Sie der Datenbank, Tabelle und / oder dem Feld die richtige Sortierung zu. (Arbeiten ohne eine ordnungsgemäße Zusammenstellung ist reine Folter)
9Rune5
0

Viel zu spät, aber ich habe dies zusammengeschmissen, um String-Vergleiche mit Platzhaltern im SQL-ähnlichen Stil durchführen zu können:

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
quelle