2016-05-13 7 views
6

私は、そのオブジェクトの1つとしてネストされたリスト(List-ChildClass)を持つオブジェクトのリスト(List-ParentClass)内のオブジェクトのリストを持っています。 List-ChildClassを設定するには、以下のようにforeachループを使用しました。私はまた、以下のようにlinqクエリをネストしました。foreachループを使用せずにC#のリスト内にリストを挿入します。もっといい方法?

この時点で私はパフォーマンス上の問題を抱えており、これを行うためのよりよい方法があると感じています。

質問:私はこれをより速く/より速く行うことができますか?

注 - これはC#で書かれたWebベースの.net MVCアプリケーションです。私はEFをSQLデータベースに戻します。

public class ParentClass 
{ 
    public int pcid { get; set; } 
    public List<ChildClass> ChildClassList { get; set; } 
} 

public class ChildClass 
{ 
    public int pcid { get; set; } 
    public int ccid { get; set; } 
} 

public class DoWork 
{ 
    public void ExampleMethodForEach() 
    { 
     List<ParentClass> ParentClassList = new List<ParentClass>(); 

     foreach(ParentClass a in ParentClassList) 
     { 
      a.ChildClassList = EFDatabase2.where(b => b.pcid == a.pcid).select(b => b.ccid).ToList(); 
     } 
    } 

    public void ExampleMethodLinq() 
    { 
     var ParentClassList = (from a in EFDatabase 
           select new ParentClass 
           { 
            ccid = a.ccid, 
            pcid = (from b in EFDatabase2 
              where b.pcid == a.pcid 
              select b.ccid).ToList() 
            //something like this were I nest a query 
           }).ToList(); 
    } 
} 
+0

* database *のパフォーマンスに問題がある場合は、 'list'、' foreach'などではなく、* database *に責任があります。最終的なクエリは何ですか?クエリが取得するレコードの数リスト内の*リストの場合は、できるだけ少数の呼び出しを行います。*すべてのデータを* 1で取得してから、必要な構造に整理できますか? –

+0

私がforeachで見つけたのは、データベースに当たる回数が問題を引き起こしていた可能性があるということでした。私の現在のアプリでは、データをメモリにプルしてから、foreachループを実行しています。これはうまくいくが、ちょっと重たく感じるようだ。私はすべてが1つの大きな質問で完了できると思っています。 – KungFuMaster

+0

レコードの量はそれほど多くなく、我々は数千または二に戻っていますが、それぞれが3〜10倍多くのレコードを含む複数のリストを持っています。また、これを引き出すためのクエリは少し複雑です。だから私の状況の詳細には、それはおそらく非常に簡単ではありません。質問:上記の方法は、この状況を解決するための通常の方法であると思いますか? – KungFuMaster

答えて

2

リレーショナルデータベースとLINQを使用する場合、を使用してデータを関連付けるときに最も良い方法は、です。あなたのケースでは、最も適切でgroup join次のとおりです。あなたに素敵な高速な単一のデータベースクエリを与える必要があります

var ParentClassList = 
    (from p in EFDatabase 
    join c in EFDatabase2 on p.pcid equals c.pcid into children 
    select new ParentClass 
    { 
     pcid = p.pcid, 
     ChildClassList = 
      (from c in children 
       select new ChildClass 
       { 
        pcid = c.pcid, 
        ccid = c.ccid 
       }).ToList() 
    }).ToList(); 

P.S.あなたのEFDatabaseEFDatabase2変数が、同じデータベース内の2つのテーブルを参照することを願っています。

+0

このソリューションは私に最高のパフォーマンスをもたらしました。正しい答えとしてマークしてください。 – KungFuMaster

0

データベースを複数回使用しています。 N + 1の問題があります。

私が示唆しているのは、すべての親を最初に照会することですが、子供のデータは除外します。次に、取得したすべての親のIDを取得し、配列内に配置します。この配列を使用してSQLにIN句を作成します。

親IDの配列を使用してすべての子をロードした後、親IDをキーとしてToLookupを使用してLookupにマップし、foreachを使用して子のリストを親に割り当てます。

var parents = EFDatabase2.Parents.Where(...).Select(p => new ParentClass { pcid = p.pcid }).ToList(); 
var ids = parents.Select(p => p.pcid).ToArray(); 
var children = EFDatabase2.Children.Where(c => ids.Contains(c.ccid)).Select(c => new ChildClass { pcid = c.pcid, ccid = c.ccid }).ToLookup(c => c.pcid); 

foreach (var parent in parents) 
{ 
    parent.Children = children[parent.pcid]; 
} 

この場合、データベースに対して2つのクエリしか実行しません。

+0

これは、私がカップルのインスタンスでやっていることに非常に似ており、パフォーマンスは "まともな"ですが、私はlinqとListにあまりにも頼っていると思います。あなたが説明したように私はそれを試してみます。 – KungFuMaster

+0

LINQとListなしでパフォーマンスが大幅に向上することは非常に疑わしいです。このprobemは、複数のDBクエリでPierre-Alainが述べたとおりです。最適なアプローチは、データベースからすべてのものを一度に(たとえばストアドプロシージャを使用して)クエリし、それをデータにマップすることです。もう1つ確認すべきことは、クエリにデータベースに適切なインデックスがあることです。パフォーマンスの問題が存在する可能性があります。 –

関連する問題