为什么Select,Where和GroupBy的这种组合会导致exception?

我有一个简单的服务表结构,每个服务都有很多设施。 在数据库中,这是一个Service表和一个Facility表,其中Facility表引用了Service表中的一行。

在我们的应用程序中,我们有以下LINQ工作:

 Services .Where(s => s.Facilities.Any(f => f.Name == "Sample")) .GroupBy(s => s.Type) .Select(g => new { Type = g.Key, Count = g.Count() }) 

但由于我无法控制的原因,源集在Where调用之前被投射到非实体对象,这样:

 Services .Select(s => new { Id = s.Id, Type = s.Type, Facilities = s.Facilities }) .Where(s => s.Facilities.Any(f => f.Name == "Sample")) .GroupBy(s => s.Type) .Select(g => new { Type = g.Key, Count = g.Count() }) 

但这引发了以下exception,没有内部exception:

EntityCommandCompilationException: The nested query is not supported. Operation1='GroupBy' Operation2='MultiStreamNest'

但是,删除Where会使其工作,这让我相信只有这种方法调用的特定组合:

 Services .Select(s => new { Id = s.Id, Type = s.Type, Facilities = s.Facilities }) //.Where(s => s.Facilities.Any(f => f.Name == "Sample")) .GroupBy(s => s.Type) .Select(g => new { Type = g.Key, Count = g.Count() }) 

有没有办法完成上述工作:选择一个非实体对象,然后在生成的可查询对象上使用WhereGroupBy ? 在Select工作之后添加ToList ,但是大型源集使得这不可行(它将在数据库上执行查询,然后在C#中对逻辑进行分组)。

此exception源自EF源代码中的这段代码……

 //  // Not Supported common processing // For all those cases where we don't intend to support // a nest operation as a child, we have this routine to // do the work. //  private Node NestingNotSupported(Op op, Node n) { // First, visit my children VisitChildren(n); m_varRemapper.RemapNode(n); // Make sure we don't have a child that is a nest op. foreach (var chi in n.Children) { if (IsNestOpNode(chi)) { throw new NotSupportedException(Strings.ADP_NestingNotSupported(op.OpType.ToString(), chi.Op.OpType.ToString())); } } return n; } 

我不得不承认:这里发生的事情并不明显,也没有技术设计文件披露所有EF的查询构建策略。 但这段代码……

 // We can only pull the nest over a Join/Apply if it has keys, so // we can order things; if it doesn't have keys, we throw a NotSupported // exception. foreach (var chi in n.Children) { if (op.OpType != OpType.MultiStreamNest && chi.Op.IsRelOp) { var keys = Command.PullupKeys(chi); if (null == keys || keys.NoKeys) { throw new NotSupportedException(Strings.ADP_KeysRequiredForJoinOverNest(op.OpType.ToString())); } } } 

在窗帘后面略微窥视一下。 我刚刚在我自己的情况下尝试了一个OrderBy ,它完全复制了你的,并且它有效。 所以我很确定如果你这样做……

 Services .Select(s => new { Id = s.Id, Type = s.Type, Facilities = s.Facilities }) .OrderBy(x => x.Id) .Where(s => s.Facilities.Any(f => f.Name == "Sample")) .GroupBy(s => s.Type) .Select(g => new { Type = g.Key, Count = g.Count() }) 

例外将消失。