LINQ-to-SQLでの大文字と小文字を区別しない文字列比較


137

大文字と小文字を区別しない文字列比較を実行するためにToUpperとToLowerを使用するのは賢明ではないことを読みましたが、LINQ-to-SQLに関しては代替手段がありません。String.CompareのignoreCaseおよびCompareOptions引数は、LINQ-to-SQLによって無視されます(大文字と小文字を区別するデータベースを使用している場合は、大文字と小文字を区別しない比較を要求しても、大文字と小文字を区別する比較が行われます)。ToLowerまたはToUpperはここで最良のオプションですか?一方が他方よりも優れていますか?私はどこかでToUpperの方が優れていると読んだと思いましたが、それがここで当てはまるかどうかはわかりません。(私は多くのコードレビューを行っており、誰もがToLowerを使用しています。)

Dim s = From row In context.Table Where String.Compare(row.Name, "test", StringComparison.InvariantCultureIgnoreCase) = 0

これは、row.Nameを「test」と単に比較し、大文字と小文字を区別するデータベースで「Test」と「TEST」を返さないSQLクエリに変換されます。


1
ありがとう!これは本当に私のお尻を救った。注:LINQQuery.Contains("VaLuE", StringComparer.CurrentCultureIgnoreCase)およびのような他のLINQ拡張機能でも動作しLINQQuery.Except(new string[]{"A VaLUE","AnOTher VaLUE"}, StringComparer.CurrentCultureIgnoreCase)ます。ワフー!
グレッグブレイ

おかしい、私はこのソースからの比較でToUpperの方が優れていたことを読んだ:msdn.microsoft.com/en-us/library/dd465121
malckier

回答:


110

あなたが言うように、ToUpperとToLowerの間にはいくつかの重要な違いがあり、大文字と小文字を区別しない等価チェックを実行しようとする場合、1つだけが信頼できる正確です。

理想的には、大文字と小文字を区別しない同等性チェックを行う最善の方法次のとおりです。

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

ただし、この場合は機能しませ。したがって、私たちは、ToUpperまたはで立ち往生していToLowerます。

なお、 ITセキュリティセーフにするためにIGNORECASEを。ただし、使用する大文字と小文字を区別する(区別する)チェックの種類は、目的が何であるかによって異なります。ただし、一般的には、並べ替えの際に等値チェックにEqualsを使用し、並べ替えるときにCompareを使用して、ジョブに適したStringComparisonを選択します。

マイケルカプラン(このような文化とキャラクターの取り扱いについて認められた権威)は、ToUpperとToLowerに関連する投稿があります。

彼は、「String.ToUpper – ToLowerではなく ToUpperを使用し、OSの大文字と小文字の規則を取得するためにInvariantCultureを指定します」と述べています


1
SQL Serverには適用されませんようだ:(「グロッセファー通り」)の上部に印刷グロースシュトラーセ返す
BlueMonkMN

1
また、提供したサンプルコードには、MS SQL 2005データベースでLINQ-to-SQLを介して実行するときに大文字と小文字を区別する限り、提供したコードと同じ問題があります。
BlueMonkMN 2009年

2
同意する。すみません、はっきりしていませんでした。私が提供したサンプルコードは、元の質問で指摘したようにLinq2Sqlでは機能しません。あなたが始めた方法は、このシナリオでのみ機能するのであれば、行くのに最適な方法であると単に言い直していました。はい、別のMike Kaplan soapboxは、SQL Serverの文字処理がいたるところにあることです。大文字と小文字を区別する必要があり、他の方法でそれを取得できない場合は、データを大文字として保存してから、大文字でクエリすることを(不明確に)提案しました。
Andrew Arnott

3
大文字と小文字を区別するデータベースがあり、大文字と小文字を混在させて格納し、大文字で検索すると、一致が得られません。検索でデータとクエリの両方を大文字にすると、すべてのクエリで検索するすべてのテキストが変換され、パフォーマンスが低下します。
Andrew Arnott、

1
@BlueMonkMN、正しいスニペットを貼り付けてもよろしいですか?MSSQL Serverが黒より赤を好むとは信じがたいです。
greenoldman

75

System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") クエリで使用し ました。

これは、大文字と小文字を区別しない比較を実行します。


3
ハ!数年前からlinq 2 sqlを使用していますが、これまでSqlMethodsを見ていませんでした。ありがとう!
CarlHörberg、2010

3
鮮やかさ!ただし、詳細を使用できます。Likeの予想される用途の1つですか?誤検知結果を引き起こす可能性のある入力はありますか?または偽陰性の結果?この方法のマニュアルはどこのドキュメントですが、不足しているだろうと同様の方法の動作を説明するには?
タスク

2
SQL Serverが文字列を比較する方法に依存していると思います。これはおそらくどこかで構成可能です。
Andrew Davey、

11
System.Data.Linq.SqlClient.SqlMethods.Like(row.Name、 "test")は、row.Name.Contains( "test")と同じです。Andrewが言っているように、これはSQLサーバーの照合に依存します。したがって、Like(またはcontains)は常に大文字と小文字を区別しない比較を実行するわけではありません。
doekman

3
これにより、コードがに結合しすぎることに注意してくださいSqlClient
Jaider 2015

5

私はラムダ式を使用してこれを試してみましたが、うまくいきました。

List<MyList>.Any (x => (String.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) && (x.Type == qbType) );


18
これは、データベースで比較を実行List<>するIQueryable(またはObjectQuery)ではなく、メモリ内(C#コード)で比較が行われることを意味するを使用しているためです。
drzaus 2016

1
@drzausが言ったこと。コンテキストがlinq2sqlであり、通常のlinqではないことを考えると、この答えは単に間違っています。
rsenna 2017年

0

大文字と小文字を区別しない文字列をLINQ-to-SQLに渡すと、SQLにそのまま渡され、データベースで比較が行われます。データベースで大文字と小文字を区別しない文字列比較を行いたい場合は、比較を行うラムダ式を作成するだけで、LINQ-to-SQLプロバイダーがその式をそのままの文字列でSQLクエリに変換します。

たとえば、このLINQクエリ:

from user in Users
where user.Email == "foo@bar.com"
select user

LINQ-to-SQLプロバイダーによって次のSQLに変換されます。

SELECT [t0].[Email]
FROM [User] AS [t0]
WHERE [t0].[Email] = @p0
-- note that "@p0" is defined as nvarchar(11)
-- and is passed my value of "foo@bar.com"

ご覧のとおり、文字列パラメータはSQLで比較されます。つまり、期待どおりに機能するはずです。


あなたの言っていることが理解できません。1).NETでは文字列自体で大文字と小文字を区別したり区別したりすることはできないため、「大文字と小文字を区別しない文字列」を渡すことはできません。2)LINQクエリは基本的にラムダ式であり、これが2つの文字列を渡す方法であるため、これは私には意味がありません。
BlueMonkMN 2009年

3
CASE-SENSITIVEデータベースでCASE-INSENSITIVE比較を実行したい。
BlueMonkMN 2009年

どのケースセンシティブデータベースを使用していますか?
Andrew Hare

また、LINQクエリはラムダ式ではありません。LINQクエリは、いくつかの部分(特にクエリ演算子とラムダ式)で構成されています。
Andrew Hare、

この回答は、BlueMonkMNのコメントとしては意味がありません。
Alf、

0

大文字と小文字を区別するLinq to Sqlクエリを実行するには、次のいずれかを使用してサーバーのデータ型を指定することにより、「string」フィールドを大文字と小文字を区別するように宣言します。

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS 

または

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

注:上記の照合タイプの「CS」は「大文字と小文字を区別する」を意味します。

これは、Visual Studio DBML Designerを使用してプロパティを表示するときに、[サーバーデータタイプ]フィールドに入力できます。

詳細については、http://yourdotnetdesignteam.blogspot.com/2010/06/case-sensitive-linq-to-sql-queries.htmlを参照してください


それが問題です。通常、私が使用するフィールドでは大文字と小文字が区別されます(化学式CO [一酸化炭素]はCo [コバルト]とは異なります)。ただし、特定の状況(検索)では、coをCoとCOの両方に一致させる必要があります。異なる "サーバーデータタイプ"で追加のプロパティを定義することは無効です(linq to sqlは、sql列ごとに1つのプロパティしか許可しません)。だからまだ行けません。
doekman

また、ユニットテストを行う場合、このアプローチはデータモックと互換性がない可能性があります。受け入れられた回答でlinq / lambdaアプローチを使用するのが最善です。
デリック

0
where row.name.StartsWith(q, true, System.Globalization.CultureInfo.CurrentCulture)

1
これが翻訳されるSQLテキストとは何ですか?それ以外の場合は大文字と小文字を区別するものとして扱うSQL環境で大文字と小文字を区別しないようにするのは何ですか?
BlueMonkMN 2013

0

次の2段階のアプローチは私にとってはうまくいきます(VS2010、ASP.NET MVC3、SQL Server 2008、Linq to SQL):

result = entRepos.FindAllEntities()
    .Where(e => e.EntitySearchText.Contains(item));

if (caseSensitive)
{
    result = result
        .Where(e => e.EntitySearchText.IndexOf(item, System.StringComparison.CurrentCulture) >= 0);
}

1
テキストが検索テキストで始まる場合、このコードにはバグがあります(> = 0である必要があります)
Flatliner DOA 2012年


0

データベースに保存された値にスペースが含まれる場合があるため、これを実行すると失敗する可能性があります

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

この問題の解決策は、スペースを削除してから大文字と小文字を変換し、次のように選択することです

 return db.UsersTBs.Where(x => x.title.ToString().ToLower().Replace(" ",string.Empty).Equals(customname.ToLower())).FirstOrDefault();

この場合の注意

customnameはデータベース値と一致する値です

UsersTBsはクラスです

タイトルはデータベース列です


-1

クエリが機能するかどうかと、効率的に機能するかどうかには違いがあることに注意してください。LINQステートメントは、ステートメントのターゲットがSQL Serverである場合にT-SQLに変換されるため、生成されるT-SQLについて考える必要があります。

String.Equalsを使用すると、おそらくSQL Serverからすべての行が返され、.NETで比較が行われます。これは、T-SQLに変換できない.NET式だからです。

つまり、式を使用すると、データアクセスが増加し、インデックスを利用する能力が失われます。小さなテーブルで動作し、違いに気付かないでしょう。大きなテーブルでは、パフォーマンスが非常に悪くなる可能性があります。

これは、LINQに存在する問題の1つです。人々は、自分が書いた声明がどのように満たされるかについてもはや考えません。

この場合、式を使用せずに必要なことを実行する方法はありません-T-SQLでもです。したがって、これをより効率的に行うことができない場合があります。上記のT-SQLの回答(照合で変数を使用)でも、ほとんどの場合、インデックスは無視されますが、テーブルが大きい場合は、ステートメントを実行し、実行プランを調べてインデックスが使用されたかどうかを確認することをお勧めします。 。


2
それは真実ではありません(行がクライアントに返されることはありません)。私はString.Equalsを使用しましたが、機能しない理由は、それがTSQL文字列比較に変換されるためです。その動作は、データベースまたはサーバーの照合に依存します。私が書いたすべてのLINQ to SQL式がどのようにTSQLに変換されるかを検討します。目的の方法への道は、ToUpperを使用して、生成されたTSQLがUPPERを使用するように強制することです。その後、変換と比較のロジックはすべてTSQLで実行されるため、パフォーマンスが大幅に低下することはありません。
BlueMonkMN 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.