web-dev-qa-db-ja.com

LINQ to SQLでcontains()を使用する

Linq-to-sqlを使用して、非常に基本的なキーワード検索をアプリケーションに実装しようとしています。私の検索用語は文字列の配列であり、各配列項目は1つのWordであり、検索用語を含む行を検索したいと思います。検索用語だけが含まれているかどうかは気にしません(おそらくそうするでしょう)が、すべての検索用語が存在する必要があります。

理想的には、以下のスニペットに似たものが欲しいのですが、これはうまくいかないことがわかっています。また、私は この質問 を見てきましたが、その質問の著者は逆のことをすることに満足しているようです(query.Contains(part.partName))、これは私には機能しません。

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where part.partName.Contains(query)
           select part;
}

このクエリを書き換えて、必要な処理を実行するにはどうすればよいですか?

38
a_m0d

他の試みを見ると悲しくなります:(

public IQueryable<Part> SearchForParts(string[] query)
{
  var q = db.Parts.AsQueryable(); 

  foreach (var qs in query)
  { 
    var likestr = string.Format("%{0}%", qs);
    q = q.Where(x => SqlMethods.Like(x.partName, likestr));
  }

  return q;
}

仮定:

  • partNameは次のようになります。「ABC 123 XYZ」

  • クエリは{"ABC"、 "123"、 "XY"}です

42
leppie

より単純でより正しい解決策(そしてleppieの):

_public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (string qs in query)
    {
        q = q.Where(x => x.partName.Contains(qs));
    }

    return q;
}
_

これは、partNameが文字列(または文字列に相当するSQL)である限り機能します。

注意すべき重要な点は、 partName.Contains(qs)query.Contains(partName) とは異なることです。
partName.Contains(qs)を使用すると、partNameの出現箇所についてqsが検索されます。結果のSQLは同等です(<qs>はqsの値です):

_select * from Parts where partName like '%<qs>%';
_

また、 StartsWithEndsWith にも注意してください。これらは Contains に似ていますが、特定の場所の文字列用。

query.Contains(partName)は、SQL in コマンドと同じです。結果のSQLは次のようになります(<query0>は_query[0]_の値、<query1>は_query[1]_の値、<queryN>はクエリ配列の最後の値)。

_select * from Parts where partName in ( <query0>, <query1>, ..., <queryN> );
_

更新:
leppieの答えは、ワイルドカード文字を like ステートメントに追加する前にエスケープしないことに注意することも重要です。 Linqはクエリを送信する前にエスケープするため、これは Contains ソリューションの問題ではありません。 _SqlMethods.Like_ソリューションのエスケープバージョンは次のようになります。

_public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (var qs in query)
    {
        string escaped_bs = qs.Replace("/", "//"),
            escaped_us = escaped_bs.Replace("_", "/_"),
            escaped_p = escaped_us.Replace("%", "/%"),
            escaped_br = escaped_p.Replace("[", "/["),
            likestr = string.Format("%{0}%", escaped_br);

        q = q.Where(x => SqlMethods.Like(x.partName, likestr, '/'));
    }

    return q;
}
_

Linqはあなたのためにそれをエスケープするので、あなたは心配する必要はありません。

20
Trisped

あなたが試すことができます:

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where query.All(term => part.partName.Contains(term))
           select part;
}

ただし、LINQ to SQLでT-SQLに変換できるかどうかはわかりません。別のオプションは次のとおりです。

public IQueryable<Part> SearchForParts(string[] query)
{
    var result = from part in db.Parts
                 select part;

    foreach(var term in query)
    {
        result = from part in result
                 where part.partName.Contains(term)
                 select part;
    }

    return result;
}

それほどきれいではありませんが、動作するはずです。 where句に多くのANDsを含むクエリを取得します。

2
Rory

このように書くことができます

var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
1
Fadrian Sudaman

NinjaNye.SearchExtension nugetパッケージを使用すると、この検索を簡単に実行できます。

string[] terms = new[]{"search", "term", "collection"};
var result = db.Parts.Search(terms, p => p.PartName);

複数の文字列プロパティを検索することもできます

var result = db.Parts.Search(terms, p => p.PartName, p.PartDescription);

または、RankedSearchを実行し、IQueryable<IRanked<T>>を返します。これには、検索語が出現した回数を示すプロパティが含まれます。

//Perform search and rank results by the most hits
var result = db.Parts.RankedSearch(terms, p => p.PartName, p.PartDescription)
                     .OrderByDescending(r = r.Hits);

プロジェクトのGitHubページには、より広範なガイドがあります。 https://github.com/ninjanye/SearchExtensions

これが将来の訪問者に役立つことを願っています

1
NinjaNye

これはやや単純で、私にとってはうまくいくと思います:

string[] product = products.Split(','); 
using (var context = new ProjectTrackerEntities()) 
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }
0
murali