2011-01-15 33 views
0

私は、次のクエリを持っている:Linq2Sql:クエリ - サブクエリの最適化

  IList<InfrStadium> stadiums = 
       (from sector in DbContext.sectors 
       where sector.Type=typeValue 
       select new InfrStadium(sector.TeamId) 
       ).ToList(); 

とInfrStadiumクラスのコンストラクタ:

private InfrStadium(int teamId) 
    { 
     IList<Sector> teamSectors = (from sector in DbContext.sectors 
            where sector.TeamId==teamId 
            select sector) 
            .ToList<>(); 
     ... work with data 
    } 

現在の実装では、n 1つの+ n個のクエリ、実行 - レコード数がフェッチを1回目。

私はそれを最適化したいと思います。

そして、私はこのような方法で、「グループ」演算子を使用して行うのが大好きだ別の1:適切なコンストラクタを持つ

  IList<InfrStadium> stadiums = 
       (from sector in DbContext.sectors 
       group sector by sector.TeamId into team_sectors 
       select new InfrStadium(team_sectors.Key, team_sectors) 
       ).ToList(); 

private InfrStadium(int iTeamId, IEnumerable<InfrStadiumSector> eSectors) 
    { 
     IList<Sector> teamSectors = eSectors.ToList(); 

     ... work with data 
    } 

しかし、クエリは次のようなエラーが発生し起動しよう:

Expression of type 'System.Int32' cannot be used for constructor parameter of type 'System.Collections.Generic.IEnumerable`1[InfrStadiumSector]'

質問1:

ここで何が間違っているのか説明してください。「team_sectors」が「System.Int32」として適用される理由を理解できませんか?

  IList<InfrStadium> stadiums = 
       (from sector in DbContext.sectors 
       group sector by sector.TeamId into team_sectors 
       select new InfrStadium(team_sectors.Key, team_sectors.AsQueryable()) 
       ).ToList(); 

適切なコンストラクタで:

私は、クエリ少しは(IQueryeableとIEnumerableを置き換える)を変更しようとしました

private InfrStadium(int iTeamId, IQueryeable<InfrStadiumSector> eSectors) 
    { 
     IList<Sector> teamSectors = eSectors.ToList(); 

     ... work with data 
    } 

この場合、私は別のが、同様のエラーを受信しました:

Expression of type 'System.Int32' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable 1[InfrStadiumSector]' of method 'System.Linq.IQueryable 1[InfrStadiumSector] AsQueryableInfrStadiumSector'

質問2:実際

、同じ質問:ここで何が起きているのか全く理解できない...

P.S. 私は質問のアイデアを最適化する別の方法があります(ここで説明する:Linq2Sql: query optimisation)が、DBへの1つのリクエストで解決策を見つけるのが大好きです。

+0

上記のコードを実装しましたが、あなたが言及したエラーは発生しませんでした。私は2つの構文エラーを修正しなければならなかったので、コードを正しくコピーしていないと思われます。あなたがコンストラクタ内で仕事をしている理由を教えてください。それは悪い習慣です。 David Bの答えはいいと思います。 – Enigmativity

+0

おそらく私の側の問題の理由は、DBにアクセスするためにはlinq2sqlを使用しますが、IQueryableインターフェイスへのアクセスを提供するBLToolkitフレームワークです。フレームワークの所有者と対話しようとします。 – Budda

+0

工作後にオブジェクトを完全に初期化したいので、Enigmativity、コンストラクタでの処理を行います。コンストラクタ内での作業が悪い習慣である理由を教えてください。 – Budda

答えて

3

まず、データをローカルに取り出し、必要に応じた構造に配置します。

ILookup<int, InfrStadiumSector> sectorLookup = 
(
    from sector in DbContext.sectors 
    where sector.Type == typeValue 
    select sector 
).ToLookup(sector => sector.TeamId); 

その後

IList<InfrStadium> stadiums = sectorLookup 
    .Select(x => new InfrStadium(x.Key, x)) 
    .ToList(); 

...(バック・データベースへ行かなくても)InfrStadiumのインスタンスにそのルックアップで各グループのプロジェクトとその投影は、このコンストラクタを使用しています。

+0

私の元の記事では、私は、orderby team_sectors.Sum(ts => ts.Size)降順のような集約式でデータを注文したいと言っていませんでした。したがって、現在のapporoachで私はクライアント側でそれを行う必要があります。それが実際にパフォーマンスに大きな違いをもたらすとは思わないでください。 – Budda

1

少しの実験がなければ何が起こっているのか分かりません。コンストラクタ内のパラメータの順序は確かですか?もしそうなら、表現を翻訳することが問題になるかもしれません。 InfrStadiumオブジェクトを構築する前に、クエリをマテリアライズしてみてください。拡張メソッドを使って書き直してみると、読みやすくなると思います。

var stadiums = DbContext.sectors 
         .ToLookup(s => s.TeamId) 
         .Select(g => new InfrStadium(g.Key, g)) 
         .ToList(); 
+0

...しかし、グループ化がデータベース内で行われた場合、SQLの「キーと集計」グループ化結果とlinqの「階層化」グループ化の違いにより、データベースから各グループの内容をフェッチするn + 1クエリになります結果。 –

+0

@David - ああ、私はそれを考えていませんでした。通常、私は集約を匿名オブジェクトにグループ化して使用します。私はToList()をチェーン内で動かす必要があると思います。 – tvanfosson

+0

@David - 第二に、あなたの考えはより良いですが、私はそれがすべて一緒につながっているのが好きです。 – tvanfosson