我有两张桌子:
block: int id, [other columns...]
blockInstance: int id, int blockId (references Block.Id), [other columns...]
我的目标是生成具有两个属性的块对象的枚举:(1)Id(块的Id)和(2)InstanceCount(块的实例数)。目前,我的XML文件不包含块实例(该表存在但行数为零)。
这是我的(非工作)查询:
var groupedBlocks =
from
b in _tableDictionary["block"].Elements()
join
bi in _tableDictionary["blockInstance"].Elements()
on b.Element(_ns + "id").Value equals bi.Element(_ns + "blockId").Value into j
from
lj in j.DefaultIfEmpty()
group
lj by b.Element(_ns + "id").Value into g
select new
{
Id = g.Key,
InstanceCount = g.Count(i => i.Element(_ns + "blockId") != null)
};
问题在于g.Count()的谓词(lambda表达式)。如果我删除谓词并只使用g.Count(),则查询会生成适当的行数,但每行的InstanceCount为1,这是错误的(它应该为零)。使用谓词,查询返回零行,如果我尝试在调试器中查看ResultsView,则会显示“异常:对象引用未设置为对象的实例”。
我最大的困惑是我的lambda表达式中 “i”的确切含义。我知道它是一个XElement,但是当数据是连接的结果时(在这种情况下,左外连接),这个XElement包含什么?
好吧,当我输入这个时我得到了一个更多的想法,它确实有效:-),但我不明白为什么:-(所以我仍然会问这个问题;-)。
如果我将违规代码更改为......
InstanceCount = g.Count(i => i != null)
......它有效。但为什么?!再次,什么是传递到lamba表达式?为什么它是空的?
谢谢!
答案 0 :(得分:2)
i 在您的群组计数中引用相当于 lj ,这是从枚举 j.DefaultIfEmpty()返回的。
此上下文中的DefaultIfEmpty()将返回项目类型的默认值,其中该项目与前一个 join..into 声明。
对于引用类型( XElement 是引用类型),默认值始终为null,这就是获取空引用异常的原因,以及为什么先检查null会删除问题
编辑:
使用子查询避免分组的替代方法:
var groupedBlocks = from b in _tableDictionary["block"].Elements() select new { Id = b.Element(_ns + "id").Value, InstanceCount = (from bi in _tableDictionary["blockInstance"].Elements() where bi.Element(_ns + "blockId").Value == b.Element(_ns + "id").Value select bi).Count() };
答案 1 :(得分:0)
传递给Count lambda的参数与您要分组的参数类型相同。那是因为您在g
IGrouping<string, XElement>
的上下文中调用了Count。
因此,i
为XElement
。
在您的第一个查询中,您实际上是在检查分组XElement
的第一个孩子,(访问i.Element
方法),这就是为什么它没有用。