2011-09-28 119 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