如果我说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<string,string> 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:
嗨Mouk,
由于我是C#的新手,我仍在苦苦挣扎,这对我不起作用。
var query = _ConfigFile.ConnectionMasterSection;
for(int i = 0; i < filter.count; i++)
{
query = result.Where(p => typeof(ConnectionMaster).GetProperty(filter[i].Attribute).Name == filter[i].Value);
}
这是空的,我用的是
var query = _ConfigFile.ConnectionMasterSection;
//Hard coded
res.Where(q => q.category == filter[0].Value);
它按预期工作。
嗨Bryan Watts,
我也尝试了你的代码,我收到了这个错误:“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<Connection, bool>>(
Expression.Equal(param, constant), Expression.Parameter(typeof(Connection),"p")));
}
这里的错误是什么?
答案 0 :(得分:5)
查看此http://www.albahari.com/nutshell/predicatebuilder.aspx,它允许强类型谓词构建,它可以非常好。如果你想要实际的动态字符串构建谓词,那么你可以使用ScottGu提供的LINQ Dynamic Query Library。
虽然我会在第二个选项之前推荐第一个选项,但两者都能达到你想要的效果。
允许你这样做:
var predicate = PredicateBuilder.True<MyLinqType>();
if(!string.IsNullOrEmpty(name))
predicate = predicate.And(p => p.name == name);
...
var myResults = Context.MyLinTypeQueryTable.Where(predicate);
还有更多。
答案 1 :(得分:3)
你走了:
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子句。
答案 2 :(得分:0)
您可以使用fluent接口并在每个条件下添加一个新的Where子句fpr。类似的东西:
var result = from cus in customers select cus;
if(!string.IsNullOrEmpty(name))
result= result.Where(p => p.Name == name);
编辑评论:
如果要查询内存中的集合,可以使用反射检索属性。
private Customer[] GetCustomers(Dictionary<string,string> 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通过反射检索属性。
使用Linq2Sql这个方法将导致检索所有记录,然后使用反射迭代它们。
答案 3 :(得分:0)
听起来你需要动态撰写查询。
它解释了编译器如何组成对IQueryable<T>
的查询,以及如何添加动态元素。
修改强>
以下是如何在Where
之上动态构建一组IQueryable<Customer>
条件的示例:
// This method ANDs equality expressions for each property, like so:
//
// customers.Where(c => c.Property1 == value1 && c.Property2 == value2 && ...);
private IQueryable<Customer> FilterQuery(IQueryable<Customer> customers, IDictionary<string, string> 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<Func<Customer, bool>>(filterExpression, parameter);
customers = customers.Where(whereBody);
}
return customers;
}
答案 4 :(得分:0)
我对Dynamic LINQ有很好的经验。
我将它用于丰富的HTML表格,可以对服务器端进行过滤和排序。服务器接收包含请求参数的请求,其中键是属性的名称(例如“Lastname”),值是属性需要排序的值(例如“Smith”)。使用该信息,我构建了一个查询字符串,并将其传递给Dynamic LINQ的Where
方法。
粗略地说,你可以想到以下内容:
public static IQueryable<T> Filter<T>(this IQueryable<T> query, Dictionary<string, string> 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注入的攻击,但您不应该让它盲目地解析所有用户输入。