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;
}
このクエリを書き換えて、必要な処理を実行するにはどうすればよいですか?
他の試みを見ると悲しくなります:(
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"}です
より単純でより正しい解決策(そして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>%';
_
また、 StartsWith
と EndsWith
にも注意してください。これらは 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はあなたのためにそれをエスケープするので、あなたは心配する必要はありません。
あなたが試すことができます:
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句に多くのAND
sを含むクエリを取得します。
このように書くことができます
var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
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);
これが将来の訪問者に役立つことを願っています
これはやや単純で、私にとってはうまくいくと思います:
string[] product = products.Split(',');
using (var context = new ProjectTrackerEntities())
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }