2012-02-14 66 views
5

我一直在這個問題上撞了一段時間。有一些類似的情況,但解決方案不適用於我的案件。動態LINQ(對實體)哪裏可以爲空的DateTime列

我有一個返回字符串格式的過濾器查詢的方法。該方法具有對不同的數據類型的邏輯,設置正確的值,列名等

string filterQuery = GetFilterQuery(params); 
rows = rows.Where(filterQuery); 

我的問題是我在數據庫Nullable DateTime和我在代碼側String表示。

我曾嘗試以下查詢(String表示可能是錯誤的目前):

"BirthDate.ToString() = \"16.2.2012 22:00:00\"" 

結果: '日期時間' 方法對類型不可訪問

"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\"" 

結果LINQ實體無法識別方法「System.String的ToString()」方法,和這種方法不能被翻譯成表達商店。

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\"" 

結果''或「(」預期

任何想法如何解決這個問題呢?

更新(增加了更多的源代碼有關查詢代)

var filterQueries = query.GridFilteringOptions.filters 
    // remove filters that doesn't have all the required information 
    .Where(o => o.name != string.Empty && o.value != string.Empty && !string.IsNullOrEmpty(o.type)) 
    // remove filters that are filtering other tables than current 
    .Where(o => o.table == tableName) 
    .Select(filter => filter.ResolveQuery()).ToList(); 

if (filterQuery.Any()) 
{ 
    var filterQuery = string.Join(" And ", filterQueries); 
    rows = rows.Where(filterQuery); 
} 

,這裏是一個類過濾器和方法與此背景有關

public string ResolveQuery() 
{ 
    if (type == "Int64") 
    { 
     return ResolveInteger(); 
    } 
    else if(type == "String") 
    { 
     return ResolveString(); 
    } 
    else if(type == "DateTime") 
    { 
     return ResolveDateTime(); 
    } 
    else 
    { 
     return string.Empty; 
    } 
} 

private string ResolveDateTime() 
{ 
    DateTime result = new DateTime(); 
    if (DateTime.TryParse(this.value, out result)) 
    { 
     return string.Format("{0}.ToString() = \"{1}\"", this.name, result.ToUniversalTime()); 
    } 
    return string.Empty; 
} 

private string ResolveString() 
{ 
    switch (@operator) 
    { 
     default: 
      return string.Format(@"{0}.StartsWith(""{1}"")", this.name, this.value); 
    }    
} 

private string ResolveInteger() 
{ 
    string tmp = this.name; 
    switch (@operator) 
    { 
     case -1: 
      return string.Empty; 
     case 0: 
      tmp += "<"; 
      break; 
     case 1: 
      tmp += "="; 
      break; 
     case 2: 
      tmp += ">"; 
      break; 
     default: 
      return string.Empty; 
    } 
    tmp += value; 
    return tmp; 
} 

回答

2

LINQ to Entities不能識別ToString()方法。在將結果字符串插入查詢之前,您必須對其進行評估。

要建立在你的問題的例子,你可能會處理這樣的:

// "BirthDate.ToString() = \"16.2.2012 22:00:00\"" 
string birthdate = BirthDate.ToString(); 
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate); 

// "BirthDate.Value.ToString() = \"16.2.2012 22:00:00\"" 
string birthdate = BirthDate.Value.ToString(); 
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate); 

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""可能不起作用,因爲LINQ到EF不承認三元運算符(? :

編輯:我從您的評論中瞭解到,BirthDate是您的表格中的一列,而不是變量。在這種情況下,你可以檢索所有條目,將其轉換爲一個列表,然後使用LINQ過濾器適用對象是這樣的(雖然你將不得不相應地修改filterQuery):

string filterQuery = GetFilterQuery(params); 
var filteredRows = rows.ToList().Where(filterQuery); 

未經測試:它可能有可能使用你的數據庫的CONVERT功能:

string query = "CONVERT(varchar(20), BirthDate) = \"16.2.2012 22:00:00\""; 
+0

BirthDate.ToString() - 在這種情況下什麼是BirthDate?在我的情況只是一個列名,所以它不存在於代碼上下文中。 – Tx3 2012-02-14 09:22:43

+0

我明白了。看看我更新的答案。 – 2012-02-14 09:34:36

+0

謝謝,我會嘗試未經測試的方法 – Tx3 2012-02-14 09:44:04

0

我的問題是,我有可爲空的DateTime在數據庫中,我有 代碼方面字符串表示。

爲什麼?

更改代碼端,解析字符串表示形式並在LINQ查詢中爲其提供適當的對象。

「BirthDate.ToString()= \」 2012年2月16日22:00:00 \ 「」

BAD - 如果你有做串manipulatzion,AWLWAYS使用InvariantCulture的。此代碼很脆弱,並會在任何其他國家/地區破解。

+0

日期字符串格式在此問題中不相關。是的,它在示例代碼中格式不正確。它可能會更改爲UTC整數。我試圖完成的是,我將有一種方法以字符串格式返回有效的「搜索標準」,以便它可以輕鬆用於所有類型的日期類型。如果有必要,我可以在可爲空的DateTime上做一個例外,但我寧願避免它。 – Tx3 2012-02-14 09:12:44

+0

你當然對InvariantCulture和當前的代碼是脆弱的。 – Tx3 2012-02-14 09:20:08

+0

無法完成。除了SQL日期時間之間的「between」之外,沒有一種有效的方法可以搜索,而LINQ可以做的僅限於此。您的通用方法更好地考慮到LINQ特性。 – TomTom 2012-02-14 09:34:15

0

我目前用try/catch塊解決這個問題。這增加了一些開銷和醜陋,我寧願找一個替代方案,但它確實很紮實工作:

try 
{ 
    // for strings and other non-nullables 
    records = records.Where(rule.field + ".ToString().Contains(@0)", rule.data); 
} 
catch (System.Linq.Dynamic.ParseException) 
{ 
    // null types 
    records = records.Where(rule.field + ".Value.ToString().Contains(@0)", rule.data); 
} 

注:接受來自輸入變量(rule.fieldrule.data)這些領域是危險的,可能會打開你直到(困難)盲目SQL注入。可以根據值的白名單檢查第一個值(rule.field),以防止出現這種情況。