2015-12-21 57 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

對不起,對這個問題的答覆太晚了。直到今天我再次遇到同樣的問題,我忘了這一切。該解決方案效果很好。謝謝。 –