2015-12-21 54 views
3

我喜欢在可能的情况下使用扩展方法编写我的查询。所以下面是对我的作品的查询:实体框架IQueryable扩展方法不能用作子查询

int studentId = 
    (
     from u in db.Users 
      .FromOrganisation(org.Id) 
      .IsStudent() 
      .IsActive() 
     where u.ExtId == dto.StudentExtId 
     select u.Id 
    ).FirstOrDefault(); 

扩展方法如下:

public static IQueryable<User> IsStudent(this IQueryable<User> u) 
{ 
    return u.Where(x => x.Type == (int)UserTypes.Student); 
} 

然而,当我使用扩展方法在一个子查询,我得到了以下信息:

LINQ实体无法识别方法“System.Linq.IQueryable`1 [eNotify.Domain.Models.User] IsActive(System.Linq.IQueryable`1 [eNotify.Domain.Models.User]) '方法,并且这种方法不能被翻译成商店表达。

这是导致该消息查询:

var vm = from o in db.Organisations 
     select new StaffStudentVm 
     { 
      StudentId = (
       from u in db.Users 
        .FromOrganisation(org.Id) 
        .IsStudent() 
        .IsActive() 
       where u.ExtId == dto.StudentExtId 
       select u.Id 
       ).FirstOrDefault(), 
      StaffId = (
       from u in db.Users 
        .FromOrganisation(org.Id) 
        .IsStaff() 
        .IsActive() 
       where u.ExtId == dto.StaffExtId 
       select u.Id 
       ).FirstOrDefault() 
     }; 

return vm.FirstOrDefault(); 

我在做什么错?

更新: Alexander Derck发布了一个运行良好的解决方案,但不像原始问题查询那么好。我与EF团队一起提出了这个问题,调查后他们提出了一个更优雅的解决方法。我已经在下面公布了接受的答案。

+0

你可以链接你的'IsActive()'方法吗?根据错误消息,您可能正在做一些无法转换为sql的内容 –

+0

这不是IsActive方法。如果我在查询中注释它,它只会报告下一个扩展方法作为问题。 –

+0

也许你可以使用表达式而不是扩展方法? –

回答

1

我最终提出这与GitHub上的实体框架团队。你可以在这里看到线程,用它为什么发生在一个完整的描述:

https://github.com/aspnet/EntityFramework6/issues/98

这似乎已经有人提出列入EF 6.2的建议,但在那之前,一个非常优雅的变通被建议。您可以在线程中阅读它,但我已将其复制到此处以供快速参考。

这里是原来的查询(其中一个错误为IQueryable扩展方法在一个子查询中使用的发生是由于):

var vm = from o in db.Organisations 
     select new StaffStudentVm 
     { 
      StudentId = (
       from u in db.Users 
        .FromOrganisation(org.Id) 
        .IsStudent() 
        .IsActive() 
       where u.ExtId == dto.StudentExtId 
       select u.Id 
       ).FirstOrDefault(), 
      StaffId = (
       from u in db.Users 
        .FromOrganisation(org.Id) 
        .IsStaff() 
        .IsActive() 
       where u.ExtId == dto.StaffExtId 
       select u.Id 
       ).FirstOrDefault() 
     }; 

return vm.FirstOrDefault(); 

这里怎么这么不发生错误写:

var stuList = db.Users.FromOrganisation(org.Id).IsStudent().IsActive(); 
var staffList = db.Users.FromOrganisation(org.Id).IsStaff().IsActive(); 

var vm = from o in db.Organisations 
     select new StaffStudentVm 
     { 
      StudentId = (
       from u in stuList 
       where u.ExtId == dto.StudentExtId 
       select u.Id 
       ).FirstOrDefault(), 
      StaffId = (
       from u in staffList 
       where u.ExtId == dto.StaffExtId 
       select u.Id 
       ).FirstOrDefault() 
     }; 

return vm.FirstOrDefault(); 

我可以确认这种风格仍然只导致1往返数据库。将查询分解为多个语句实际上也提高了许多地方的可读性。

0

可以进行部分类为您User模型内部静态类:

partial class User 
{ 
    public static class Q 
    { 
     public static Expression<Func<User,bool>> IsStudent 
     { 
      return x => x.Type == (int)UserTypes.Student; 
     } 
    } 
} 

然后将查询应该是这样的:

var vm = from o in db.Organisations 
    select new StaffStudentVm 
    { 
     StudentId = (
      from u in db.Users 
       .FromOrganisation(org.Id) 
       .Where(User.Q.IsStudent) 
       .IsActive() 
      where u.ExtId == dto.StudentExtId 
      select u.Id 
      ).FirstOrDefault(), 
     StaffId = (
      from u in db.Users 
       .FromOrganisation(org.Id) 
       .IsStaff() 
       .IsActive() 
      where u.ExtId == dto.StaffExtId 
      select u.Id 
      ).FirstOrDefault() 
    }; 

这并不是因为扩展方法一样优雅,但它应该做的伎俩,我认为...

+0

谢谢我明天就试试看,并报告回来...... –

+0

对不起,对这个问题的答复太晚了。直到今天我再次遇到同样的问题,我忘了这一切。该解决方案效果很好。谢谢。 –