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)<- 是的,一个帐户可能有多个订单,同样,一个订单可能与多个帐户相关联。
  • 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();

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

问题围绕多对多表的过滤最大日期展开。一个额外的复杂性是我们需要按过滤后的最大值进行排序,并且我们必须在不破坏我们急切加载的情况下完成上述所有操作(即,连接必须通过 Where 中的投影完成,而不是使用 .Join)。我不确定如何执行此查询,而不会使结果比应有的复杂 10 倍。我不想进行连接以过滤 ao.OrderStatus/Max DateToExecute 3 次(一次用于 startDate,一次用于 stopDate,一次用于排序)。显然 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 回答