【发布时间】:2011-04-12 15:59:08
【问题描述】:
对于单元测试,我们使用内存集合来验证 LINQ 查询的逻辑。但是,在下面的场景中,我看到 LINQ to SQL 与内存中的结果之间存在差异。
对于这个例子,我们有三个表 Customer、Order、Item。我想要客户订购的所有商品的计数。我也想向没有订购任何商品的客户展示。在 SQL 中,这将是一个外连接。在 LINQ to SQL 中,我写了这个...
var itemCounts =
from c in Customer
from o in Order.Where(oo=>o.CustomerId==c.CustomerId).DefaultIfEmpty()
from i in Item.Where(ii=>i.OrderId==o.OrderId).DefaultIfEmpty()
group i by new { i.ItemId, c.CustomerId } into ig
select new ItemCountResult {
CustomerId = ig.Key.CustomerId,
Count = ig.Count()
};
当我们针对数据库时,这可以正常工作。我们得到有订单和没有订单的客户以及数量。当我们用内存集合代替单元测试时,我们会看到对象引用未设置异常。我已将其缩小到“i.OrderId==o.OrderId”这一行,特别是 o 为空。
根据“DefaultIfEmpty”的工作原理,这实际上是我所期望的行为。 DefaultIfEmpty 返回一个可枚举的 null 元素。
那么如何修复此代码以在这两种情况下工作?
更新: 当我简化问题时,我丢失了一些重要的信息。所以让我重申一下这个问题。
一个客户有 0-n 个订单。 一个订单有 1-n 个项目。 一个项目有 1-n 顺序。
我需要商品列表以及订购该商品的客户数量。如果有 0 位客户订购了该商品,我希望它仍然被退回,但计数为 0。
问题是 Order 和 Item 之间的多对多,这使我无法使用 join-into 语法。
我目前有这样的东西(希望这次没有打错):
var counts =
from i in Items
from oi in OrderItems.Where(z=>z.ItemId==i.ItemId).DefaultIfEmpty()
from o in Orders.Where(z=>z.OrderId==oi.OrderId).DefaultIfEmpty()
from c in Customers.Where(z=>z.CustomerId==o.CustomerId).DefaultIfEmpty()
group c by new { i.ItemId, c.CustomerId } into cg
select new CountResult {
CustomerId = cg.Key.CustomerId,
Count = cg.Count()
};
【问题讨论】:
标签: linq linq-to-sql