2011-09-28 57 views
0

我試圖解決的真實世界問題:我有一個數據庫,其中一串電話號碼以絕對可怕的格式存儲爲字符串(例如「(02)9971 1209」) 。我的程序的用戶將開始輸入電話號碼,當他鍵入時,他正在輸入的內容將被髮送並用於使用「startswith」操作過濾數據庫中的電話號碼列表。將lambda表達式翻譯爲表達式樹

問題是,如果用戶鍵入「02997」,它不會匹配任何內容,因爲數字與括號中的位置代碼一起存儲。爲了這個操作的工作,用戶必須鍵入「(」這不是好的開始每一個搜索

TL;博士版本在問題的底部

我把。問題出它的真實世界場景和成更小的,密封的解決方案,我可以專注於它沒有大規模的代碼庫的干擾在這種情況下,我的解決辦法是做一些LINQ trickiness:

class Program 
{ 
    static string [] phones = {"(02) 9489 3048","(04) 1128 2148","(01) 9971 1208",}; 

    static void Main(string[] args) 
    { 
     for (;;) 
     { 
      Console.WriteLine("Enter your number: "); 
      string input = Console.ReadLine(); 

      Func<string, string> strip = 
      tehstring => tehstring.Where(x => char.IsDigit(x)) 
            .Aggregate("", (x, y) => x + y); 
      var results = phones.Where(z => strip(z).StartsWith(strip(input))); 

      foreach (var x in results) 
       Console.WriteLine(x); 
     } 
    } 
} 

這是所有的好,完美的作品,完全符合我的需要,但它只適用於這個孤立的角落xt:我無法將其移回到需要實現的代碼庫中,因爲我需要將它翻譯爲表達式樹。

,我需要怪人下來代碼:

static Expression GetOperationExpression(
    StringFilterOperation operation, 
    Expression propertyExpression, 
    Expression valueExpression) 
{ 
    switch (operation) 
    { 
    case StringFilterOperation.StartsWith: 
    var startsWith = typeof(string) 
        .GetMethod("StartsWith", new Type[] { typeof(string) }); 
    Contract.Assume(startsWith != null); 
    return Expression.Call(propertyExpression, startsWith, valueExpression); 
    //etc etc etc 

我需要propertyExpression,和(電話號碼錶在這種情況下,在外部DB)以某種方式將它嵌入在談論財產在我的lambda函數中。然後我需要將整個事件反編譯回表達式樹並返回。

這就是我卡住的地方。我能想出的最好的是一個超級長和不雅LINQ的行甚至沒有反正正確類型:

Expression<Func<string[],string, IEnumerable<string>>> expr = 
(db, uinput) => db.Where(z => z.Where(x => char.IsDigit(x)) 
           .Aggregate("", (x, y) => x + y) 
           .StartsWith(uinput.Where(x => char.IsDigit(x)) 
               .Aggregate("",(x,y) => x + y))); 

我想要做這樣的事情,這仍然不能解決問題但稍微整齊:

Expression<Func<string, string>> strip = 
tehstring => tehstring.Where(x => char.IsDigit(x)) 
         .Aggregate("", (x, y) => x + y); 
Expression<Func<string, string, string>> query = 
(db, uinput) => db.Where(z => strip(z) 
        .StartsWith(strip(uinput))); 

我試過對它應用大量的小改動,但它拒絕編譯。

TL;博士:

長話短說,我需要做的只是代表一個數據庫表字段的表達式和變換表達成一個代表同樣的事情,但應用的過濾器可以清除所有不是數字的字符。

回答

5

很多希望用來獲取電話號碼剝離版本的表達式可能不會被LINQ提供者支持。

我個人建議製作一個數據庫查看,顯示所有電話號碼的精簡格式。然後,您可以針對該視圖執行標準StartsWith查詢。

+1

對,特別是沒有'char.IsDigit'。 –

+0

我擔心這可能是這種情況。無論如何,我仍然想嘗試使用我的linq提供程序,因爲更改電話號碼的格式是不行的。我也會看看你的數據庫視圖的建議 – TheIronKnuckle

+0

@TheIronKnuckle:另一種選擇是在數據庫中創建一個用戶定義的函數,並在你的linq查詢中調用它。無論哪種方式,你都必須在數據庫上創建一些東西,因爲我無法想出使用LINQ to SQL或LINQ to Entities實現的方法來做什麼的問題。換句話說,即使你編譯了它,它也會在運行時拋出一個異常。 – StriplingWarrior