- PR -

LINQ: 複数キーワード(string配列)に対し LIKE したい

投稿者投稿内容
Shane
大ベテラン
会議室デビュー日: 2003/06/06
投稿数: 132
お住まい・勤務地: Vancouver, BC
投稿日時: 2008-10-11 02:00
複数のキーワード(string配列)に対し LINQ で LIKE 構文を実行したいのですが、どのようにすればいいのかわかりません。

例えば以下のプログラムのような感じで、以下では Contains() なので完全一致してなくては条件に引っかかりませんが、そこを部分一致(LIKE)で引っかかるようにしたいのです。

string[] keywords = new string[] {"a", "b", "c"}

bindingSource.DataSource =
from n in dc.Contacts
where keywords.Contains(n.CompanyName)
select n;

どなたかわかる方がいましたらアドバイスよろしくお願いします。
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-11 02:57
delegate bool K(string s);


K k = delegate(string s) {
for (int i=0;i < keywords.count;i++)
if (keywords[i].indexOf(s) > -1) return true;
return false;
}


from n in dc.Contcts where k(n.COmpanyName) select n;

とか。

http://msdn.microsoft.com/ja-jp/library/0yw3tz5k(VS.80).aspx


Shane
大ベテラン
会議室デビュー日: 2003/06/06
投稿数: 132
お住まい・勤務地: Vancouver, BC
投稿日時: 2008-10-11 04:53
NotSupportedException が出てしまいました。

Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.
かるあ
ぬし
会議室デビュー日: 2003/11/16
投稿数: 1190
お住まい・勤務地: センガワ→ムサシノ
投稿日時: 2008-10-11 10:37
引用:

ぴあちゃんさんの書き込み (2008-10-11 02:57) より:

コード:
K k = delegate(string s) {
   for (int i=0;i < keywords.count;i++) 
      if (keywords[i].indexOf(s) > -1) return true;
   return false;
}




試してないんだけれど、delegate じゃダメなんじゃ。。。
ラムダにしたらどうなります?
_________________
かるあ のメモスニペット
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-11 13:20
http://msdn.microsoft.com/ja-jp/library/bb397687.aspx

ほんとうだ。

ラムダ式ね。。

〜以上とどうやって内部的に区別してんだろ?・・・
<追記>
次の例は、複数の入力パラメータをかっこで囲んで指定する方法を
示しています。このメソッドは、値がその位置よりも小さい数値が出現す
るまで配列 numbers に含まれるすべての要素を返します。ラムダ演算子
(=>) と以上演算子 (>=) を混同しないようにしてください。

俺はアホや・・・ => そー言えば "=>" は 等号の演算子じゃないよね・・・
</追記>




http://msdn.microsoft.com/ja-jp/library/bb397947.aspx



[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2008-10-11 13:26 ]

[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2008-10-11 13:35 ]

[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2008-10-11 13:49 ]
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-11 17:57
こんなんでどーでしょう。

拡張メソッドを組み合わせてみました。


コード:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyExtends;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<MyClass> list = new List<MyClass>();

            //collect "def" includeed
            list.Add(new MyClass("cdefg", 1));
            list.Add(new MyClass("CDEFG", 1));
            list.Add(new MyClass("CVdef", 1));

            string[] strs = { "def", "axf", "wer" };

            IEnumerable<MyClass> result = 
                    from n in list 
                    where strs.ContainsLike(n._A)
                    select n;

            foreach (MyClass a in result)
            {
                Console.WriteLine(a._A);

            }

            Console.In.ReadLine();

        }
    }

    class MyClass
    {
        public string _A;
        public int _B;
        public MyClass(string a, int b)
        {
            _A = a;
            _B = b;
        }
    }
}





コード:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyExtends
{
    class Class1
    {
    }

    public static class MyExtends
    {

        public static bool ContainsLike(this IEnumerable<string> ss, string s1)
        {
            foreach (string q in ss)
            {
                if (s1.IndexOf(q) > -1) return true;
            }
            return false;
        }

    }

}




ya
大ベテラン
会議室デビュー日: 2002/05/03
投稿数: 212
投稿日時: 2008-10-11 22:20
Linq to Objects だったら

コード:

bindingSource.DataSource = 
  from n in dc.Contacts 
  where keywords.Any(k => n.CompanyName.Contains(k))
  select n;



これでいいんじゃねって感じだけど例外見た感じ、Linq to SQL っぽい?のかな。そうなると生成された SQL 眺めて色々試していかないといけないかも。
最後の手段としては Where に渡す Expression を動的に生成するってのが思いつきますがそれは「えー?」みたいな気もするので何か方法がありそう。

# ごめんなさい、Linq to SQL の個別の云々はあまりわからんです
ya
大ベテラン
会議室デビュー日: 2002/05/03
投稿数: 212
投稿日時: 2008-10-12 13:25
Linq to SQL だと仮定していわゆる「えー?」なコード書いてみました。
ワンライナーで書いちゃったけど中身は(一応)難しいことはしていないはず。
コード:


var keywords = new[] { "a", "b]", "c%b" };

var param = Expression.Parameter(typeof(Contacts), "n");
var expr = Expression.Lambda<Func<Contacts, bool>>(
keywords
.Select(
// keyword を like パターンに
keyword =>
"%" + String.Concat(
keyword.Select(c => @"\" + c ).ToArray()
) + "%"
)
.Select(
// Like 式の生成
// pattern => Like(n.CompanyName, pattern, escape(='\\') )
(pattern) => (
// Like(n.CompanyName, keyword, '\\\')
(Expression)Expression.Call(
typeof(SqlMethods).GetMethod(
"Like",
new[]{
typeof(string),
typeof(string),
typeof(char)
}
),
// n.CompanyName
Expression.Property(
param,
"CompanyName"
),
// "[pattern]"
Expression.Constant(pattern),
// '\\\'
Expression.Constant('\\\')
)
)
)
.Aggregate(
// 式を OrElse で全結合
// (prev, e) => prev || e
(prev, e) => Expression.OrElse(prev, e)
),
param
);

bindingSource.DataSource = dc.Contacts.Where(expr);



不明なところ(Contacts の型名とか)もあるので通らないかもしれないけども。

# OrElse でいいの?ちなみに


[ メッセージ編集済み 編集者: ya 編集日時 2008-10-12 13:39 ]

スキルアップ/キャリアアップ(JOB@IT)