如何在EF4中按筛选的Max查询进行查询和排序?

时间:2012-04-19 19:13:39

标签: c# sql-server linq entity-framework entity-framework-4

上下文: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)< - 是的,一个帐户可能有多个订单,同样,一个订单可能与多个帐户相关联。
  • OrderedItem (long Id, long OrderId, long ItemId, etc)< - 一个订单可能有很多项目,我们希望加载这些项目(我意识到这会影响性能/数据大小)。

伪代码(几乎是实际代码),非常适合工作:

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();

在英语中,这是在寻找在日期范围内执行最后一个订单的下五个帐户。但是,也有可以取消的订单,因此我们必须在执行该Max时排除42的OrderStatus。

问题围绕多对多表中过滤的Max日期。增加的复杂性是我们需要按照过滤的最大值进行排序,我们必须完成上述所有操作而不会破坏我们的预期加载(即连接必须通过Where中的投影来完成,而不是使用.Join)。我不确定如何进行此查询而不会导致10x的结果比它应该更复杂。我讨厌做连接来过滤ao.OrderStatus / Max的DateToExecute 3次(一次用于startDate,一次用于stopDate,一次用于排序)。显然,IsBetween不起作用。

有关如何执行此查询的任何想法,以这种方式排序,以相当有效的方式生成SQL吗?

1 个答案:

答案 0 :(得分: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();

这是未经测试的,因为我没有任何数据源可供测试。但它可能是您需要做的最简单的方法。