2017-10-15 23 views
1

請參閱calculateAge將LINQ查詢中的出生日期轉換爲當前年數(它適用於其他鍵,例如:EyeColor,但適用於年齡轉換失敗),我想比較存儲在數組中的值。我嘗試將值存儲在鏈接上方的DateTime temp變量中,正好在「case」AgeTo「:」下方,但我不能將值x.profile.BirthDate存儲爲僅在LINQ Query中允許的值。看來,在構建LINQ查詢,不給錯誤,但是,它的失敗精讀從LINQ查詢日期時間字段中計算年齡(使用C#進行比較)(Age From)

錯誤:

LINQ to Entities does not recognize the method 'Int32 calculateAge(System.DateTime)' method, and this method cannot be translated into a store expression.

任何幫助,如何處理?

代碼和calculateAge方法:

if (searchList.Count > 0) 
{ 
    foreach (KeyValuePair<String, String> kvp in searchList) 
    { 
     switch (kvp.Key) 
     { 
      case "AgeFrom": 
       photosquery = photosquery.Where(x => calculateAge(Convert.ToDateTime(x.profile.BirthDate)) >= Convert.ToInt32(kvp.Value)); 
       break; 
      case "AgeTo": 
       photosquery = photosquery.Where(x => calculateAge(Convert.ToDateTime(x.profile.BirthDate)) <= Convert.ToInt32(kvp.Value)); 
       break; 
      case "EyeColor": 
       photosquery = photosquery.Where(x => x.physical.EyesColor.Contains(kvp.Value)); 
       break; 
     } 
    } 
} 

//My code for calculateAge: 

public static int calculateAge(DateTime birthDay) 
{ 
    int years = DateTime.Now.Year - birthDay.Year; 

    if ((birthDay.Month > DateTime.Now.Month) || (birthDay.Month == DateTime.Now.Month && birthDay.Day > DateTime.Now.Day)) 
     years--; 

    return years; 
} 
+0

你知道如果你在午夜附近執行你的代碼,如果可能會失敗嗎?最好在當前時間只詢問一次,以確保搜索列表中的所有項目都使用相同的時間進行比較。也更容易編寫一個體面的規範:「該函數計算函數被調用時集合中所有項目的年齡」。無論程序執行的速度如何,結果都是可預測的。另外考慮使用DateTime.Today,而不是DateTime.Now –

+0

好的一點,我會改變代碼,回到我的成功。 – dotNETEngineer

回答

1

這裏有一個簡單的解決方案。比較年齡,比較日期本身。

case "AgeFrom": 
    var fromAge = Convert.ToInt32(kvp.Value); 
    var maxDate = DateTime.Today.AddYears(-fromAge); 
    photosquery = photosquery.Where(x => x.profile.BirthDate <= maxDate); 
    break; 
case "AgeTo": 
    var toAge = Convert.ToInt32(kvp.Value); 
    var minDate = DateTime.Today.AddYears(-toAge-1).AddDays(1); 
    photosquery = photosquery.Where(x => x.profile.BirthDate >= minDate); 
    break; 

這使得查詢sargable,所以它可以使用索引的,假設你的好處已經創建了一個在BirthDate場。

+0

謝謝你的幫助馬特JOHnson,這對我有效。 BirthDate字段是DateTime字段,它可以與轉換後的maxDate或minDate變量進行比較。我很感謝幫助。 – dotNETEngineer

+0

有人可以回答以下(類似)的問題嗎?這一次我需要與數值進行比較。 https://stackoverflow.com/questions/46855132/convert-to-int-from-string-from-linq-query-field-using-c-sharp-for-comparison-h – dotNETEngineer

2

你得到這個錯誤的原因是你的Where -clause被調用你的實體可查詢,它不知道怎麼翻譯的C#代碼轉換爲數據庫語言的等價物。

如果您能夠將該函數的內部函數重寫爲沒有基於.NET的變量存儲或僅引用數據庫中可用的CLR函數的內容,則可以使用它內聯,噸有函數調用:

var now = DateTime.Now; 
...  
case "AgeFrom": 
    photosquery = photosquery.Where(x => DbFunctions.DiffYears(x.profile.BirthDate,now) >= Convert.ToInt32(kvp.Value)); 
    break; 

如果你想使用你儘管代碼,你將需要過濾,這一般不建議使用之前檢索所有數據。您仍然可以通過在.Where(..)子句之前調用.ToList()來實現此目的。

+0

感謝羅布,看起來像我想念你的評論。我會試試看。 – dotNETEngineer

+1

Rob,我得到了它與馬特的迴應,感謝您的幫助。 DbFunctions類也相當實用。我會爲未來的計算留下一張便條。 – dotNETEngineer

+0

嗨,有人可以查看SQL語法,並幫助我 - - https://stackoverflow.com/questions/47849473/select-statement-has-case-that-provies-select-value-sql-server – dotNETEngineer

0

您正在使用IQuearyable,因此在實現之前您不能將其與任意C#代碼混合使用。

現在你有兩個選擇:

  1. 加載所有的數據到應用程序內存ToListToArray並應用濾波方法
  2. 重寫查詢使用一些sql功能(DATEPART這種情況)

對於您可以編寫此查詢(switch前)第二種方式:

var newQuery = photosquery.Select(x => new 
{ 
    AllQuery = x, 
    yearsDiff = (x.profile.BirthDate.Month > now.Month) || 
       (x.profile.BirthDate.Month == now.Month 
        && x.profile.BirthDate.Day > now.Day) 
     ? now.Year - x.profile.BirthDate.Year - 1 
     : now.Year - x.profile.BirthDate.Year 
}); 

然後,當你進入你的switch你可以寫:

case "AgeFrom": 
    photosquery = newQuery 
     .Where(x => x.yearsDiff >= Convert.ToInt32(kvp.Value)) 
     .Select(x => x.AllQuery); 
    break; 
+0

有趣,謝謝,我會嘗試... – dotNETEngineer

相關問題