2014-09-22 50 views
0

我需要在IQueryable<T>.Select語句中運行自定義方法,例如,IQueryable中的自定義方法<T>。選擇

query.Select(r => new ResultObject() 
{ 
Id = r.Persion.Id, 
Code = r.Person.Code, 
CalculatedField = CalculateField(r.Person) 
} 

問題是,我不能像這樣運行它,因爲引發了linq-to-sql異常。 CalculateField基本上是一個switch語句:

private static CalcFieldEnum CalculateField(Person p) 
{ 
    if(p.Age < 21) 
    { 
     if(p.Salary > 2000 && p.YearsWorked > 2) 
      return CalcFieldEnum.TypeB; 
     else if(p.YearsWorked <= 2) 
      return CalcFieldEnum.TypeC; 
    } 
    else 
    { 
     if(p.Salary > 3000) 
      return CalcFieldEnum.TypeB; 
    } 

    return CalcFieldEnum.TypeA; 
} 

的事項有關的方法(CalculateField)的唯一的事情是,它只是需要一些實體,並返回結果基於實體的字段值。

我無法運行此方法後查詢,因爲用戶可以按列排序結果,也可以在IQueryable上排序運行。有什麼辦法可以解決這個問題嗎?

P.S我簡化了方法的邏輯,在現實中有很多更多的if-else語句的。這個想法是相同的,但它只是返回一個基於對象字段的枚舉值。

回答

0

您可以使用AsEnumerable方法從數據庫獲取和負荷記錄,然後用你想要的任何方法:

query.AsEnumerable().Select(...); 
+0

太棒了,會有一些排序問題(按字段名排序),但這些都是可以解決的。我最關心的是性能 - 通過在本地執行排序會不會影響性能? – Arnthor 2014-09-22 13:32:27

+0

這取決於你在db中有多少條記錄。在這種情況下,我通常會在數據庫中進行篩選,獲取結果並在內存中執行其他_unsupported_操作。在你的情況下,我認爲它不應該太重要。你將最終獲取記錄 – 2014-09-22 13:35:35

2

如果你可以重寫方法的拉姆達,例如

p => p.Age < 21 
    ? (
     (p.Salary > 2000 && p.YearsWorked > 2) 
      ? CalcFieldEnum.TypeB 
      : (p.YearsWorked <= 2 ? CalcFieldEnum.TypeC : CalcFieldEnum.TypeA) 
    ) 
    : (p.Salary > 3000 ? CalcFieldEnum.TypeB : CalcFieldEnum.TypeA); 

那麼你應該可以將它傳遞給數據庫。

+0

對不起,我沒有提到if-else語句很長,所以用三元運算符重寫它會產生一個不可讀的混亂。 – Arnthor 2014-09-22 13:24:55

+1

@Arnthor好吧,這是一個不可讀的混亂和本地執行它(和隨後的排序)之間的混淆。 – Rawling 2014-09-22 13:26:08

+1

所以你會反對在大集合上進行本地排序? – Arnthor 2014-09-22 13:34:43