0

LINQ where 句を実行して : の varchar フィールドをコレクションに分割し、これを別のコレクションと比較して値が一致するかどうかを確認することは可能ですか。

たとえば、List<string>ARR ACC などを含む AllowedHolders という名前があります。ただし、データベースのフィールド (残念ながら変更できません) は varchar ですが、コロンで区切られた値を持っています: つまり、「:ARR:ACC:」

やりたいことは、AllowedHolders のいずれかがフィールドに表示されるかどうかを確認できる LINQ where 句を作成することです。フィールドに AllowedHolders コレクションの値が含まれているレコードのみを返すように結果を制限したいためです。

フィールドに単一の値のみが含まれている場合、次のことを行いました

searchResults = searchResults.Where(S => searchParams.AllowedBusinessAreas.Contains(S.SIT_BusinessArea));

ただし、SIT_HolderNames にはコロンで区切られた値が含まれているため、次の例は機能しません。

searchResults = searchResults.Where(S => searchParams.AllowedHolders.Contains(S.SIT_HolderName)

どんなアイデアでも大歓迎です。さらに説明が必要な場合は、お知らせください。

アンディ

4

3 に答える 3

2

Intersect()Any()およびを使用しString.Split()ます。

searchResults = searchResults.Where(s => searchParams.AllowedHolders.Intersect(S.SIT_HolderName.Split(':')).Any());

例えば:

":ACC:TEST::ARR:".Split(':') -> string[] { "", "ACC", "TEST", "", "ARR", "" };  

空の文字列を考慮したくない場合は、String.Split(char[], StringSplitOptions.RemoveEmptyEntries) を使用してください。

":ACC:TEST::ARR:".Split(new char[] {':'}, StringSplitOptions.RemoveEmptyEntries) -> string[] { "ACC", "TEST", "ARR" };

アップデート

String.Split()を使用して呼び出す前に、データをフェッチする必要がありますToList()

searchResults = searchResults.ToList().Where(s => searchParams.AllowedHolders.Intersect(S.SIT_HolderName.Split(':')).Any());

のデータsearchResultsが大きすぎる場合は、主キーとSIT_HolderName.

var keys = searchResults.Select(s => new { Key = s.SIT_PKey, SIT_HolderName = s.SIT_HolderName })
                        .ToList()
                        .Where(s => searchParams.AllowedHolders.Intersect(s.SIT_HolderName.Split(':')).Any())
                        .Select(s => s.Key)
                        .ToList();

searchResult = searchResults.Where(s => keys.Contains(s.SIT_PKey));

上記のクエリのパフォーマンスがどうなるかわかりません。それ以外の場合は、次のように試すことができますJoin()

searchResult = searchResults.Join(keys, s => s.SIT_PKey, key => key, (s, key) => s);
于 2013-01-30T11:53:03.313 に答える
1

Maybe you can use:

searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(H))
  );

or

searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(S.SIT_HolderName.Contains)
  );

As pointed out by the first comment, this only works if no holder name contains another holder name as a substring. I was implicitly assuming that all your holder names were three-letter strings like ARR and ACC. If this is not the case, consider using (":" + H + ":"), or find a more safe solution.

Edit: Just for completeness, here are two versions with colons prepended and appended:

// OK if some name is contained in another name as a substring
// Requires colon before the first and after the last name
searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(":" + H + ":"))
  );

And:

// OK if some name is contained in another name as a substring
// Ugly checks included to handle cases where no colons are present in the extreme ends
searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(":" + H + ":") || S.SIT_HolderName.StartsWith(H + ":") || S.SIT_HolderName.EndsWith(":" + H) || S.SIT_HolderName == H)
  );
于 2013-01-30T12:15:45.657 に答える
0

DB 列の値で、セパレーターが実際に次の形式になっている場合:

:AAA:BBB:CCC:DDD:

だけでなく (最初と最後の文字に注意してください!)

AAA:BBB:CCC:DDD

LIKE次に、ルックアップを実行できます。

select .... from ... where column LIKE '%:BBB:%'

これは LINQ に変換されます。

var idWithColons = ":" + "BBB" + ":";

from ... where .... column.Contains(idWithColons)

考えられる多くの IDS では、以下を作成する必要があります。

select .... from ... where column LIKE '%:BBB:%' OR column LIKE '%:DDD:%' OR ..

これは LINQ に変換されます。

var idWithColons = ":" + "BBB" + ":";
var idWithColons2 = ":" + "DDD" + ":";

from ... where .... column.Contains(idWithColons) or column.Contains(idWithColons2)

しかし、それは少数の選択肢にのみ適しています。ID の不明なリストについては、動的に構築されたフィルターとして書き直すことができますが、慣れていない場合はそれほど簡単ではありませんExpression<Func<>>..とにかく、LIKE による検索はとにかくあまり良い考えではありません..しかし、それは他の多くのオプションではありません:/

そうでなければ、まあ、それはきれいではありません..おそらく、SQLサーバーでスカラー値関数を準備し、それを何らかの方法でlinqプロバイダーに登録できますが、それだけの価値があるとは思いません..

編集:

where-clause を動的に構築する方法について説明します。ここhttp://www.albahari.com/nutshell/predicatebuilder.aspx - PredicateBuilder を探します。ビルダーは実際には汎用的であり、直接使用できますが、OR-LIKE を連結する小さなループを自分で作成する必要があります。この記事は十分によく書かれていると思いますが、問題があればお知らせください。パフォーマンスを除いて。LIKE %% は高速ではありません。

于 2013-01-30T11:57:16.643 に答える