57
IQueryable<Organization> query = context.Organizations;

Func<Reservation, bool> predicate = r => !r.IsDeleted;

query.Select(o => new { 
    Reservations = o.Reservations.Where(predicate)
}).ToList();

此查询会引发“内部 .NET Framework 数据提供程序错误 1025”异常,但下面的查询不会。

query.Select(o => new { 
    Reservations = o.Reservations.Where( r => !r.IsDeleted)
}).ToList();

我需要使用第一个,因为我需要检查一些 if 语句来构造正确的谓词。我知道在这种情况下我不能使用 if 语句,这就是我将委托作为参数传递的原因。

我怎样才能使第一个查询工作?

4

5 回答 5

44

虽然上述答案是正确的,但请注意,在 select 语句之后尝试使用它时,必须AsQueryable()显式调用,否则编译器将假定我们正在尝试使用 IEnumerable 方法,该方法期望 aFunc而不是Expression<Func>

这可能是原始海报的问题,否则编译器大部分时间都会抱怨它正在寻找Expression<Func>而不是Func.

演示:以下将失败:

MyContext.MySet.Where(m => 
      m.SubCollection.Select(s => s.SubItem).Any(expr))
         .Load()

虽然以下将起作用:

MyContext.MySet.Where(m => 
      m.SubCollection.Select(s => s.SubItem).AsQueryable().Any(expr))
         .Load()
于 2014-02-26T17:32:50.933 回答
26

创建赏金(老鼠!)后,我找到这个答案,它解决了我的问题。(我的问题涉及到一个.Any()电话,这比这个问题要复杂一些......)

简而言之,这是您的答案:

IQueryable<Organization> query = context.Organizations;

Expression<Func<Reservation, bool>> expr = r => !r.IsDeleted;

query.Select(o => new { Reservations = o.Reservations.Where(expr) })
  .ToList();

阅读引用的答案,了解为什么需要局部变量expr,并且不能直接引用另一种返回类型的方法Expression<Func<Reservation, bool>>

于 2012-12-13T14:52:49.663 回答
21

谢谢你ping我。我想我毕竟是在正确的轨道上。

无论如何,重申一下,LINQ to Entities(感谢 Jon Skeet 在我在评论中混淆了自己的思维过程时纠正了我)在Expression Trees上运行;它允许投影将 lambda 表达式转换为 SQLQueryProvider

常规Func<>适用于LINQ to Objects。

因此,在这种情况下,当您使用实体框架时,传递给 EF 的任何谓词IQueryable都必须是Expression<Func<>>.

于 2012-12-13T18:59:26.547 回答
5

我只是在不同的情况下遇到了这个问题。

我有一个充满Expression谓词的静态类,然后我可以将其组合或传递给 EF 查询。其中之一是:

    public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
        IEnumerable<EventEnums.AttendeeStatus> statuses)
    {
        return ce => ce.Event.AttendeeStatuses
            .Where(a => a.ClientId == ce.Client.Id)
            .Select(a => a.Status.Value)
            .Any(statuses.Contains);
    }

由于Contains方法组调用,这引发了 1025 错误。实体框架需要一个Expression并找到一个方法组,这导致了错误。将代码转换为使用 lambda(可以隐式转换为表达式)修复了错误

    public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
        IEnumerable<EventEnums.AttendeeStatus> statuses)
    {
        return ce => ce.Event.AttendeeStatuses
            .Where(a => a.ClientId == ce.Client.Id)
            .Select(a => a.Status.Value)
            .Any(x => statuses.Contains(x));
    }

旁白:然后我将表达式简化为ce => ce.Event.AttendeeStatuses.Any(a => a.ClientId == ce.Client.Id && statuses.Contains(a.Status.Value));

于 2016-03-08T12:48:23.607 回答
0

有类似的问题。如下所示的 ViewModel 库:

public class TagViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static Expression<Func<SiteTag, TagViewModel>> Select = t => new TagViewModel
    {
        Id = t.Id,
        Name = t.Name,
    };

这有效:

var tags = await db.Tags.Take(10).Select(TagViewModel.Select)
    .ToArrayAsync();

但是,这不会编译:

var post = await db.Posts.Take(10)
    .Select(p => new {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).Select(TagViewModel.Select)
    })
    .ToArrayAsync();

因为第二个.Select是一团糟——第一个实际上是从一个 ICollection 中调用的,它不是 IQueryable,所以它把第一个 Expression 当作普通的Func,而不是Expression<Func.... 返回IEnumerable<...,如本页所述。所以.AsQueryable()救援:

var post = await db.Posts.Take(10)
    .Select(p => new {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
            .Select(TagViewModel.Select)
    })
    .ToArrayAsync();

但这会产生一个新的、更奇怪的问题:要么我得到 Internal Framework...Error 1025,要么我得到带有完全加载.Post属性的 post 变量,但该.Tags属性有一个似乎用于延迟加载的 EF 代理对象。

解决方案是通过结束使用 Anonymous 类来控制标签的返回类型:

public class PostViewModel
{
    public Post Post { get; set; }
    public IEnumerable<TagViewModel> Tags { get; set; }

现在选择它,一切正常:

var post = await db.Posts.Take(10)
    .Select(p => new PostViewModel {
        Post = p,
        Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
            .Select(TagViewModel.Select)
    })
    .ToArrayAsync();
于 2017-12-21T01:11:25.767 回答