2017-06-13 4 views
0

私はLINQとかなり新人です。私は基本的なことをすることができますが、私は専門家が必要です。LINQ - AND、NOTとNOTクエリ

私はEntity Frameworkを使用していますが、私は3つの列を持つテーブルを持っています。

public class Aspect 
{ 
    [Key, Column(Order = 0)] 
    public int AspectID { get; set; } 
    [Key, Column(Order = 1)] 
    public int AspectFieldID { get; set; } 
    public string Value { get; set; } 

} 

私は、ユーザーの入力から3つの単語リストを持っています。 1つはValueフィールド(AND)になければならないフレーズまたはワードを含み、もう1つはValueフィールド(ANY)になくてもよいフレーズまたはワードを含み、最後のリストにはフレーズまたはワードが含まれますValueフィールド(NOT)。

すべての単語、すべての単語、およびNOT単語のいずれもがないすべてのレコードを取得する必要があります。

ここに私のオブジェクトがあります。

public class SearchAllWord 
{ 
    public string Word { get; set; } 
    public bool includeSynonoyms { get; set; } 
} 

public class SearchAnyWord 
{ 
    public string Word { get; set; } 
    public bool includeSynonoyms { get; set; } 
} 

public class SearchNotWord 
{ 
    public string Word { get; set; } 
} 

私がこれまで持っていることは

var aspectFields = getAspectFieldIDs().Where(fieldID => fieldID > 0).ToList();//retrieves a list of AspectFieldID's that match user input 
var result = db.Aspects 
    .Where(p => aspectFields.Contains(p.AspectFieldID)) 
    .ToList(); 

任意およびすべてのヘルプは高く評価され、これです。

+0

これは私のオブジェクトです。これは意味をなさない。オブジェクトがデータベースに存在しない場合は、Entity Frameworkを使用していません。 – Aron

+0

申し訳ありません@Aron、単語を保持するオブジェクトはデータベースにありません。それらはユーザーからの入力です。 'Aspect'オブジェクトはデータベースにあります。希望が助けてくれる – JohZant

答えて

1

最初に、これがあなたの要件であれば、あなたの質問はデータベースのすべてのレコードを読み込みます。これは遅い操作になるだろう。

IQueryable<Aspect> query = db.Aspects.AsQueryable(); 

    //note, if AllWords is empty, query is not modified. 
foreach(SearchAllWord x in AllWords) 
{ 
    //important, lambda should capture local variable instead of loop variable. 
    string word = x.Word; 
    query = query.Where(aspect => aspect.Value.Contains(word); 
} 

foreach(SearchNotWord x in NotWords) 
{ 
    string word = x.Word; 
    query = query.Where(aspect => !aspect.Value.Contains(word); 
} 

if (AnyWords.Any()) //haha! 
{ 
    List<string> words = AnyWords.Select(x => x.Value).ToList(); 
    query = 
    from aspect in query 
    from word in words //does this work in EF? 
    where aspect.Value.Contains(word) 
    group aspect by aspect into g 
    select g.Key; 
} 

あなたは〜2100パラメータの上限を意識すると、SQL Serverにこのクエリを送信している場合。各単語はパラメータとして送信されます。そして、あなたが必要なもの

+0

私はそれを「苦労しています」。これは、「無効な表現用語 'by'」と言っています。私はそれが長い時間がかかることを間違いなく理解しています。この表は非常に大きくなると予想されます。 – JohZant

+1

@DavidB - あなたが言及する非効率性は、LinqよりもEFの欠点です。インデックススキャンとして表現される方法でLinq2sqlでこれを行うことができます。 –

+0

@PeterWoneインデックススキャンはテーブルスキャンです。ここでの問題は 'string.contains'はO(n)よりも効率的な方法では行えないことです(フルテキスト検索を使用する場合を除く)。 – Aron

0

集合演算子があり、特に

  • 交差
  • どれ

バンドルアップ文字列配列(または他のいくつかの列挙)にあなたの「すべて」の言葉と、あなたはそれらがすべて存在することを確認するために交差とカウントを使用できます。ここ

は、AはBのスーパーセットである?二組

var A = new string[] { "first", "second", "third" }; 
var B = new string[] { "second", "third" }; 

ありますか

var isSuperset = A.Intersect(B).Count() == B.Count(); 

AはBとは切り離されていますか?

var isDisjoint1 = !A.Intersect(B).Any(); 
var isDisjoint2 = !A.Any(a => B.Any(b => a == b)); //faster 

オブジェクトは文字列ではないため、overload that allows you to supply a comparator functionが必要です。


そして今やいくつかのソープボックス。

私はLinq2sqlが大好きですが、ASP.NET Coreでは使用できません。EFチームはそれをそのまま維持したいと思います。おそらく私のようなジャークは「EFの総効率の悪いXがLinq2Sqlには当てはまらない」と言っているからです。

コアは未来です。、小型、高速かつクロスプラットフォーム、それはあなたがWindowsのIOT またはLinuxを実行しているラズベリーパイからWeb APIを提供することができます - またはビッグハードウェア上で途方もなく高いパフォーマンスを得ます。

EFはないが、おそらくプラットフォームを利用するのを防ぐに依存しないというプラットフォームを、上の主張しながら、それはあなたから離れて制御がかかるため、高いパフォーマンスを命題になることはありませんでしょう。

Linq2sqlが存在しない場合、ソリューションはDapperのようなライブラリのように見えます.Dapperはクエリを送信したときにパラメータを処理し、結果が到着したらオブジェクトグラフにマップします。これにより、多かれ少なかれプラットフォームにとらわれませんが、SQLをパススルーするパラメータの置き換え以外にも、プラットフォームを悪用することができます。

+0

私は少しこれを読んでいるかもしれませんが、私はAspect.Valueが単一の単語だとは思いません。このため、ソリューションは完全一致以上のものを必要とします。 –

+0

@DavidB、あなたは正しいです!これは文にすることができます。はい、私は変数を少し良くすることができたことを認識しています。これが解決された後、これを行うのを見るかもしれません。ハハ。 – JohZant

+0

私が提供しようとしている価値は、Linqを使って比較を設定するための簡単な紹介です。そして、いくつかの抗EFのsoapboxing :) –