1

コンテキスト: EF4、C#、.NET4、SQL2008/R2

問題を再現するテーブル/エンティティ:

  • Account (long Id, string Name, etc.)
  • Order (long Id, DateTime DateToExecute, int OrderStatus, etc.)
  • AccountOrder (long Id, long AccountId, long OrderId)<- はい、1 つのアカウントに多くの注文があり、同様に、1 つの注文が多くのアカウントに関連付けられている場合があります。
  • OrderedItem (long Id, long OrderId, long ItemId, etc)<- 1 つの注文に多くのアイテムが含まれる場合があり、これらのアイテムを熱心にロードしたい (これにはパフォーマンス/データ サイズの影響があることを認識しています)。

動作するのに理想的な疑似コード (ほぼ実際のコード):

DateTime startDateInclusive = xxxx;
DateTime stopDateExclusive = yyy;

var query = Db.Accounts.Include(a => a.AccountOrders.Select(ao => ao.Order.Ordereditems.Select(oi => oi.Item)))
              .Where(account =>
                     account.AccountOrders.Where(ao => ao.OrderStatus != 42)
                            .Max(ao => ao.DateToExecute).IsBetween(startDateInclusive, stopDateExclusive))
              .OrderBy(account =>
                       account.AccountOrders.Where(ao => ao.OrderStatus != 42)
                              .Max(ao => ao.DateToExecute));

var results = query.Take(5).ToList();

英語では、これは日付範囲内で実行される最後の注文がある次の 5 つのアカウントを探しています。ただし、キャンセルできるオーダーもありますので、その Max.

問題は、多対多のテーブル全体でこのフィルター処理された最大日付を中心に展開します。さらに複雑なのは、フィルター処理された最大値で並べ替える必要があり、熱心な読み込みを中断することなく上記のすべてを実行する必要があることです (つまり、結合は、.Join を使用せずに、Where のプロジェクションを介して実行する必要があります)。結果が本来よりも10倍複雑になることなく、このクエリを実行する方法がわかりません。ao.OrderStatus/Max の DateToExecute を 3 回 (startDate に 1 回、stopDate に 1 回、ソートに 1 回) フィルタリングするために結合を実行するのは嫌です。そして明らかに IsBetween は機能しません。

生成された SQL に対してかなり効率的な方法で、この方法で並べ替えられたこのクエリを実行する方法についてのアイデアはありますか?

4

1 に答える 1

1

ここで匿名型を使用すると役立つ場合があります。

DateTime startDateInclusive = xxxx;
DateTime stopDateExclusive = yyy;

var query = Db.Accounts
              .Select(account => new { 
                  Account = account,
                  MaxDate = account.AccountOrders.Select(ao => ao.Order).Where(o => o.OrderStatus != 42).Max(o => o.DateToExecute) 
              })
              .Where(a => a.MaxDate >= startDateInclusive && a.MaxDate < stopDateExclusive)
              .OrderBy(a => a.MaxDate)
              .Select(a => a.Account)
              .Include(a => a.AccountOrders.Select(ao => ao.Order.Ordereditems.Select(oi => oi.Item)));

var results = query.Take(5).ToList();

テストするデータソースがないため、これはテストされていません。しかし、それはおそらくあなたがしなければならないことに対する最も簡単なアプローチです。

于 2012-04-19T20:13:35.360 に答える