【问题标题】:ASP.NET search form - dynamic Linq to SQL?ASP.NET 搜索表单 - 动态 Linq to SQL?
【发布时间】:2009-10-12 20:03:29
【问题描述】:

我有一个搜索表单,允许用户以几种不同的方式搜索多个不同的字段。这是我的代码示例。

var claims = from c in db.Claims select c;

switch (ddlSearchField.Text)
{
    case "StartsWith":
        claims = claims.Where(c => c.companyFileID.StartsWith(txtSearchBox.Text));
        break;

    case "Equals":
        claims = claims.Where(c => c.companyFileID == txtSearchBox.Text);
        break;

    case "Contains":
        claims = claims.Where(c => c.companyFileID.Contains(txtSearchBox.Text));
        break;
}

我有大约十个不同的字段可供用户搜索,因此我的外部 switch 语句非常大。必须有一种更优雅的方式来实现这一点。

【问题讨论】:

    标签: asp.net linq linq-to-sql


    【解决方案1】:

    您可以通过创建扩展方法来重构代码的某些部分。类似的东西:

    static class QueryableExtensions
    {
        private static MethodInfo StringContainsMethod;
        private static MethodInfo StringStartsWithMethod;
    
        static QueryableExtensions()
        {
            Type[] singleStringParam = new[] {typeof(string)};
            StringContainsMethod = typeof(string).GetMethod("Contains", singleStringParam);
            StringStartsWithMethod = typeof(string).GetMethod("StartsWith", singleStringParam);
        }
    
        public static IQueryable<T> AppendTextFilter<T>(this IQueryable<T> queryable, Expression<Func<T, string>> memberSelector, string condition, string value)
        {
            Expression expression = null;
            switch (condition)
            {
                case "StartsWith":
                    expression = Expression.Call(
                                    memberSelector.Body,
                                    StringStartsWithMethod,
                                    Expression.Constant(value));
                    break;
    
                case "Equals":
                    expression = Expression.Equal(
                                    memberSelector.Body,
                                    Expression.Constant(value));
                    break;
    
                case "Contains":
                    expression = Expression.Call(
                                    memberSelector.Body,
                                    StringContainsMethod,
                                    Expression.Constant(value));
                    break;
    
                default:
                    throw new NotSupportedException(string.Format("'{0}' is not a supported condition", condition));
            }
    
            var lambda = Expression.Lambda<Func<T, bool>>(
                            expression,
                            memberSelector.Parameters);
            return queryable.Where(lambda);
        }
    }
    

    你可以这样使用它:

    var claims = db.Claims
                 .AppendTextFilter(c => c.companyFileID, ddlSearchField.Text, txtSearchBox.Text)
                 .AppendTextFilter(c => c.someOtherProperty, ddlOtherSearchField.Text, txtOtherSearchBox.Text)
                 ...;
    

    【讨论】:

    • 您好,Thomas,您的解决方案看起来很棒,并且非常接近我正在寻找的解决方案。将“声明”变量设置为 gridview 的数据源是否安全?我刚试了一下,收到一条错误消息。
    • 抱歉,错误消息是:方法'System.Object DynamicInvoke(System.Object[])' 没有支持的SQL转换。
    • 好的,我明白了问题... Linq to SQL 无法将委托调用转换为 SQL 表达式,因此它失败了。我会尝试找到解决方案并更新我的答案
    • 好的,我修复了代码以使用表达式而不是委托。我只用一个列表对其进行了测试,但我认为它应该适用于 Linq to SQL。请告诉我!
    • 非常好。如果你想要 == 而不是 .Equals(),你可以使用 Expression.Equal(memberSelector.Body, Expression.Constant(value))。
    【解决方案2】:

    您是否尝试过动态 LINQ?它允许您构建类似于 SQL WHERE 子句的基于字符串的查询语句。

    http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

    【讨论】:

      【解决方案3】:

      你可以为你可能的谓词制作一个字典:

      Dictionary<string, Func<string, Expression<Func<Claim, bool>>>> map = new Dictionary<string, Func<string, Expression<Func<Claim, bool>>>>() {
          { "StartsWith", t => c => c.companyFileID.StartsWith(t) },
          { "Equals",     t => c => c.companyFileID == t },
          { "Contains",   t => c => c.companyFileID.Contains(t) }
      };
      

      可以这样使用:

      var search = ddlSearchField.Text;
      var text = txtSearchBox.Text;
      
      var claims = from c in db.Claims select c;
      
      Func<string, Expression<Func<Claim, bool>>> predicate = null;
      if(dict.TryGetValue(search, out predicate))
          claims = claims.Where(predicate(text));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-22
        • 2011-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        相关资源
        最近更新 更多