4

私は、誰かがユーザーの名前や名前でユーザーを検索できるようにするUIを作成しています。たとえば、名に「Mike」、姓に「Jo」と入力すると、「Mike Jones」、「Mike Johnson」、「MikeJobs」が返されます。この検索には、次のLINQステートメントを使用します。

var users = (from u in context.TPM_USER
             where u.LASTNAME.ToLower().Contains(LastName.ToLower())
             && u.FIRSTNAME.ToLower().Contains(FirstName.ToLower())
             select u);

(大文字と小文字を区別しないlike句を実行するためのより良い方法がある場合とない場合がありますが、これは機能するようです)

問題は、ユーザーが名または姓を入力した後、他のフィールドを空のままにした場合です。名に「Mike」と入力し、[Last Name]フィールドを空白のままにすると、名前に関係なくすべてのMikeを返します。上記のクエリは、両方のフィールドに少なくとも何かが入力されていない限り、結果を返しません。

私は試した:

var users = (from u in context.TPM_USER
             where (LastName == "" || u.LASTNAME.ToLower().Contains(LastName.ToLower()))
             && (FirstName == "" || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
             select u);

ただし、両方のフィールドに入力しない限り、結果は得られません。私はデバッガーの下でそれLastName == ""が確かに真実であることを確認しました。

アップデート:

もう少しデバッグを行いましたが、これは実際にはOracleの問題です。生成されるクエリは次のとおりです。

--Replaced the field list with * for brevity
SELECT * FROM TPMDBO.TPM_USER "Extent1"
     WHERE (('jones' = '') OR ((INSTR(LOWER("Extent1".LASTNAME), LOWER('jones'))) > 0)) AND (('' = '') OR ((INSTR(LOWER("Extent1".FIRSTNAME), LOWER(''))) > 0))

一見正しいように見えます。ただし、Oracleはフレーズを正しく短絡していないようです('' = '')。実際、私がそうするなら:

select * from TPM_USER where '' = ''

行がゼロになります。このクエリをどのように作成するかを知るには、Oracleの専門家では不十分ですが、どちらにしても、EntityFrameworkの方言のバグです。

4

5 に答える 5

10

条件付きで述語を追加するだけです。

var users = from u in context.TPM_USER select u;
if (!string.IsNullOrWhiteSpace(FirstName))
    users = users.Where(u => u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()));
if (!string.IsNullOrWhiteSpace(LastName))
    users = users.Where(u => u.LASTNAME.ToLower().Contains(LastName.ToLower()));

または、LASTNAME 述語のみを条件として使用します。

後で追加:

のような表現Where(u => u.FIRSTNAME.ToLower()...は避けた方がよいでしょう。FIRSTNAMEフィールド値が最初に変換されてから比較されるため、インデックスが無視されます (詳細については、こちらを参照してください)。

これらの小文字への変換が必要ない可能性は十分にあります。フィールドのデータベース照合を確認してください。大文字と小文字を区別しない (CI) 場合は、おそらくそうですが、これらの変換は必要ありません。

于 2012-06-07T16:49:56.557 に答える
2

FirstName と LastName が null でないことは確かですか?

代わりに、このように書いてみてください...

string LowerFirstName = (FirstName + "").ToLower();
string LowerLastName = (LastName + "").ToLower();

var users = (from u in context.TPM_USER
             where (LowerLastName == "" || u.LASTNAME.ToLower().Contains(LowerLastName))
             && (LowerFirstName == "" || u.FIRSTNAME.ToLower().Contains(LowerFirstName))
             select u);
于 2012-06-07T16:51:47.590 に答える
1

参考までに、誰かが Oracle でこの問題に遭遇した場合、次の回避策があります。

var users = (from u in context.TPM_USER
             where (LastName == null|| u.LASTNAME.ToLower().Contains(LastName.ToLower()))
             && (FirstName == null || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
             select u);

これは次のように変換されます:

'' is null

SQL では、Oracle はこれを true と解釈します。

于 2012-06-07T20:43:17.253 に答える
0

クエリの周りに条件ステートメントを作成するだけです。

if (String.IsNullOrWhiteSpace(LastName) && !String.IsNullOrWhiteSpace(FirstName))
{
   var users = (from u in context.TPM_USER
   where (u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
   select u);
}
else if (String.IsNullOrWhiteSpace(FirstName) && !String.IsNullOrWhiteSpace(LastName))
{
   var users = (from u in context.TPM_USER
   where (u.LASTNAME.ToLower().Contains(LastName.ToLower()))
   select u);
}
于 2012-06-07T16:50:16.623 に答える
0

検索語の長さをチェックして、Oracle PL/SQL で機能しているかどうかを確認してみてください。

var users = (from u in context.TPM_USER
         where ((LastName ?? "").Trim().Length == 0 || u.LASTNAME.ToLower().Contains(LastName.ToLower()))
         && ((FirstName ?? "").Trim().Length == 0 || u.FIRSTNAME.ToLower().Contains(FirstName.ToLower()))
         select u);
于 2012-06-09T16:38:29.883 に答える