我有一个customer
实体,其记录我希望能够通过多个任意属性进行搜索。
E.g:
Dictionary<string, string> searchList = new Dictionary<string, string>();
searchList.Add("LastName", "Foo");
searchList.Add("FirstName", "Bar");
我当然可以写下这些内容:
foreach (KeyValuePair<string, string> kv in searchList)
{
switch (kv.Key)
{
case "FirstName" :
List<Customer> someResultPart = this._dbSet.Where(customer => customer.FirstName == kv.Value).ToList();
break;
case "LastName" :
// etc.
}
}
// Do intersection of all result parts ...
除了查询n
次并且稍后相交的事实显然是非常丑陋的事实之外,我宁愿在那里没有switch
声明(因为它会迫使我每次都改变它) Customer
班级中的任何内容都会发生变化。
有没有办法:
searchList
字典构建查询,从而无需switch
构造?答案 0 :(得分:1)
您可以使用Dynamic LINQ
string predicate = String.Format("{0} = \"{1}\"", kv.Key, kv.Value);
List<Customer> someResultPart = _dbSet.Where(predicate);
或者这样:
List<Customer> someResultPart = _dbSet.Where("{0}");
我甚至构建了完整的搜索谓词:
Dictionary<string, object> searchList = new Dictionary<string, object>();
searchList.Add("LastName", "Foo");
searchList.Add("FirstName", "Bar");
searchList.Add("Id", 42); // yep, not only strings
var conditions = searchList.Select((kvp, i) => String.Format("{0} = @{1}", kvp.Key, i));
string predicate = String.Join(" and ", conditions);
object[] values = searchList.Select(kvp => kvp.Value).ToArray();
var query = _dbSet.Where(predicate, values);
答案 1 :(得分:1)
对于第二点,你可以这样做:
IQueryable<Customer> filtered = this._dbSet;
foreach (KeyValuePair<string, string> kv in searchList)
{
switch (kv.Key)
{
case "FirstName" :
filtered = filtered
.Where(customer => customer.FirstName == kv.Value);
break;
case "LastName" :
// etc.
}
}
List<Customer> resultList = filtered.ToList();
答案 2 :(得分:1)
是类型安全的!
最好构造一个返回良好属性的函数列表,而不是声明一个字符串变量,如果有一天你想改变你的列名,它将会失败:
public class Customer { public string FirstName; public string LastName;}
public class CustomerFilter { public Func<Customer, string> Selector; public string Filter; }
[TestMethod()]
public void DynamicFilterTest()
{
var jonSkeet = new Customer() { FirstName = "Jon", LastName = "Skeet" };
var joelOnSoftware = new Customer() { FirstName = "Joel", LastName = "OnSoftware" };
var customers = new List<Customer>() { jonSkeet, joelOnSoftware };
var jonSkeetFilters = new List<CustomerFilter>() {
new CustomerFilter() { Selector = c => c.LastName, Filter = "Skeet" },
new CustomerFilter() { Selector = c => c.FirstName, Filter = "Jon" }};
var query = customers.AsEnumerable();
foreach (var filter in jonSkeetFilters)
{
query = query.Where(c => filter.Selector.Invoke(c) == filter.Filter);
}
var result = query.ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(jonSkeet, result.Single());
}
然后,您可以轻松地重构为您的任何参与者使用相同的模式:
public class WhereClause<T>
{
private readonly Func<T, string> _selector;
public Func<T, string> Selector { get { return _selector; } }
private readonly string _value;
public string Value { get { return _value; } }
public WhereClause(Func<T, string> selector, string value)
{
this._selector = selector;
this._value = value;
}
/// <summary>
/// Append the where clause to the given query
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public IEnumerable<T> AppendTo(IEnumerable<T> query)
{
return query.Where(c => this.Selector.Invoke(c) == this.Value);
}
/// <summary>
/// Append the wheres clauses to the given query
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public static IEnumerable<T> AppendTo(IEnumerable<T> query, IEnumerable<WhereClause<T>> wheres)
{
var filteredQuery = query;
foreach (var where in wheres)
{
filteredQuery = where.AppendTo(filteredQuery);
}
return filteredQuery;
}
}
[TestClass]
public class WhereClauseTests
{
public class Customer { public string FirstName; public string LastName;}
[TestMethod()]
public void WhereClauseTest()
{
var jonSkeet = new Customer() { FirstName = "Jon", LastName = "Skeet" };
var joelOnSoftware = new Customer() { FirstName = "Joel", LastName = "OnSoftware" };
var customers = new List<Customer>() { jonSkeet, joelOnSoftware };
var jonSkeetWheres = new List<WhereClause<Customer>>() {
new WhereClause<Customer>(c => c.LastName, "Skeet"),
new WhereClause<Customer>(c => c.FirstName, "Jon" )
};
var query = WhereClause<Customer>.AppendTo(customers, jonSkeetWheres);
var result = query.ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(jonSkeet, result.Single());
}
}