LINQ中的动态查询

如果我说Customer字段包含字段,我如何为Linq编写动态查询:

string name string address int phoneno 

我必须根据类似的信息进行查询

 query = string.Empty; if(!string.IsNullorEmpty(name)) { query += "@name = name"; } if(!string.IsNullorEmpty(address)) { query += "@address = address"; } if(!string.IsNullorEmpty(phoneno)) { query += "@phoneno = phoneno"; } var result = from condition in customer where(query) select condition; 

编辑#1:

这些项目在运行时可以更改

 private Customer[] GetCustomers(Dictionary attributes) { here the attribute may be, name alone, or name and address, or name address and phoneno foreach(string field in attributes.key) { query += field == attributes[key]; } Customers[] =ExecuteQuery(query); } 

LINQ是否支持这种查询?

编辑#2:

嗨,穆克,
由于我是C#的新手,我仍然在苦苦挣扎,这对我不起作用。

 var query = _ConfigFile.ConnectionMasterSection; for(int i = 0; i  typeof(ConnectionMaster).GetProperty(filter[i].Attribute).Name == filter[i].Value); } 

这是空的,我用这个

 var query = _ConfigFile.ConnectionMasterSection; //Hard coded res.Where(q => q.category == filter[0].Value); 

它按照我的预期工作。

嗨布莱恩沃茨,
我也尝试了你的代码,我收到了这个错误:“Lambda参数不在范围内”。

 for(int i = 0; i < filter.count; i++) { Field item = filter[i]; MemberExpression param = Expression.MakeMemberAccess(Expression.Parameter(typeof(Connection), "p"), typeof(Connection).GetProperty(item.Attribute)); MemberExpression constant = Expression.MakeMemberAccess(Expression.Constant(item), typeof(Field).GetProperty("Value")); } try { var myquery = Queryable.Where(coll, Expression.Lambda<Func>( Expression.Equal(param, constant), Expression.Parameter(typeof(Connection),"p"))); } 

这里的错误是什么?

看看这个http://www.albahari.com/nutshell/predicatebuilder.aspx ,它允许强类型谓词构建,它可以非常好。 如果你想要实际的动态字符串构建谓词,那么你可以使用ScottGu提供的LINQ动态查询库 。

虽然我会在第二个选项之前推荐第一个选项,但两者都能达到你想要的效果。

允许你这样做:

 var predicate = PredicateBuilder.True(); if(!string.IsNullOrEmpty(name)) predicate = predicate.And(p => p.name == name); ... var myResults = Context.MyLinTypeQueryTable.Where(predicate); 

和更多。

干得好:

 var result = from customer in Customers where string.IsNullOrEmpty(phoneNo) || customer.PhoneNo == phoneNo where string.IsNullOrEmpty(address) || customer.Address == address select customer; 

如果您担心这会在下面生成最佳SQL查询,那么您应该始终附加SQL查询分析器并进行检查。 但我相信Linq To Sql中的表达式解析器将根据参数的值合适地折叠where子句。

您可以使用fluent接口并在每个条件中添加新的Where子句fpr。 就像是:

  var result = from cus in customers select cus; if(!string.IsNullOrEmpty(name)) result= result.Where(p => p.Name == name); 

编辑评论:

如果要查询内存中的集合,可以使用reflection检索属性。

 private Customer[] GetCustomers(Dictionary attributes) { var result = from cus in customers select cus; foreach(string key in attributes.Keys) result= result.Where(p => GetProperty(p, key )== attributes[key]); return result.ToList(); } 

假设GetProperty通过reflection检索属性。

使用Linq2Sql这个方法将导致检索所有记录,然后使用reflection迭代它们。

我对Dynamic LINQ有很好的经验。

我将它用于一个可以过滤和排序服务器端的丰富HTML表。 服务器接收包含请求参数的请求,其中键是属性的名称(例如“Lastname”),值是属性需要排序的值(例如“Smith”)。 使用该信息,我构建了一个查询字符串,并将其传递给Dynamic LINQ的Where方法。

粗略地说,您可以想到以下内容:

 public static IQueryable Filter(this IQueryable query, Dictionary dictionary) { Type t = typeof(T); StringBuilder sb = new StringBuilder(); PropertyInfo[] properties = t.GetProperties(); foreach(string key in dictionary.Keys) { PropertyInfo property = properties.Where(p => p.Name == key).SingleOrDefault(); if(property != null) { if (sb.Length > 0) sb.Append(" && "); string value = dictionary[key]; sb.Append(string.Format(@"{0}.ToString().Contains(""{1}"")", key, value)); } } if (sb.Length > 0) return query.Where(sb.ToString()); else return query; } 

代码超出了我的头脑,因此未经测试。

当然,这是最基本的版本:它进行简单的字符串比较。 如果你想进行数值比较(意味着你想要的用户,其中UserID正好是100,而不是UserID.ToString().Contains("100") ),或查询嵌套属性(例如Customer.Company.CompanyAddress )或查询集合,这变得更复杂。 您还应该考虑安全性:虽然Dynamic LINQ不容易受到SQL注入的攻击,但您不应该让它盲目地解析所有用户输入。

听起来你需要动态组合查询。

看看我对这个问题的回答 。

它解释了如何对编译器组成IQueryable查询,以及如何添加动态元素。

编辑

下面是一个如何在IQueryable之上动态构建Where条件的示例:

 // This method ANDs equality expressions for each property, like so: // // customers.Where(c => c.Property1 == value1 && c.Property2 == value2 && ...); private IQueryable FilterQuery(IQueryable customers, IDictionary filter) { var parameter = Expression.Parameter(typeof(Customer), "c"); Expression filterExpression = null; foreach(var filterItem in filter) { var property = typeof(Customer).GetProperty(filterItem.Key); var propertyAccess = Expression.MakeMemberAccess(parameter, property); var equality = Expression.Equal(propertyAccess, Expression.Constant(filterItem.Value)); if(filterExpression == null) { filterExpression = equality; } else { filterExpression = Expression.And(filterExpression, equality); } } if(filterExpression != null) { var whereBody = Expression.Lambda>(filterExpression, parameter); customers = customers.Where(whereBody); } return customers; }