LINQ to Entities中的条件投影

8

我对一个单一实体(带有一些导航属性)有一个查询,需要将它们投影到一个模型中,以供API客户端使用。大致看起来像这样:

repository.CreateQuery<Reviews>()
  .Where(/* criteria */)
  .Select(m => new
    {
      ID = m.ID,
      Reviewers = m.IsAnonymous 
        ? m.Reviewers.Take(1).Select(r => new { Name = "Anonymous" })
        : m.Reviewers.Select(r => new { Name = r.Name })
    })

LINQ to Entities在运行时无法执行此操作。在Visual Studio调试器中,异常信息为“不支持指定的方法”。在LinqPad中,内部异常是“不支持嵌套查询。Operation1='Case' Operations2='Collect'”。
有什么办法可以解决这个问题吗?我不想强制查询执行以获取内存中的对象,因为这个条件查询的目的是为了解决性能问题,所以据我所知,我确实需要在L2E查询的范围内解决这个问题。
更新:在我的实际应用程序中,投影类型并不是匿名的。我只是在这里使用匿名类型,因为这样方便构建示例。同样地,真实的查询涉及许多其他属性,这意味着从映射表中获取更多的数据。

你为什么要使用.Take(1).Select()而不是直接使用new { Name = "Anonymous" } - Bobson
@Bobson 因为结果必须是 IEnumerable。不幸的是,LINQ-to-Entities 无法将更明显的选择数组和列表转换为 IEnumerable(除非我漏掉了什么技巧)。此外,如果有帮助的话,上面示例中的匿名类型在我的实际应用程序中都是定义良好的。 - Ben Collins
@LukeMcGregor 那个方法可以行得通,但它并不能解决我的问题。解决性能问题的方法是不对匿名评论者进行底层查询,如果我按照你的建议只选择字符串,那么我将检索到很多数据,这些数据将被丢弃。此外,您可能没有看到,但我在上面添加了一条评论,说明在我的实际应用程序中,投影类型不是匿名的。我会更新问题以反映这一点。 - Ben Collins
查询两次,加上对“m.IsAnonymous”的附加过滤器?然后使用.Concat()连接结果。 - Bobson
我怀疑在正确的查询语法中使用let语句会起作用... - jessehouwing
显示剩余2条评论
1个回答

5
您可以使用 union 来实现您想要的功能:
var query1 = repository.CreateQuery<Reviews>()
                       .Where(/* criteria */);
var queryAnonimous = query1.Where(m=>m.IsAnonymous)
                           .Select(m => new
                                        {
                                            ID = m.ID,
                                            Reviewers = m.Reviewers.Take(1).Select(r => new { Name = "Anonymous" })        
                                        })

var queryNotAnonymous =  query1.Where(m=>!m.IsAnonymous)
                               .Select(m => new
                                            {
                                                ID = m.ID,
                                                Reviewers = m.Reviewers.Select(r => new { Name = r.Name })
                                            })
var unionQuery = queryAnonimous.union(queryNotAnonymous);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接