2012-10-30 44 views
1

我有一個customer實體,其記錄我希望能夠通過多個任意屬性進行搜索。如何通過多個任意值來搜索實體?

如:

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次,後來相交顯然是fugly,我寧願沒有那switch聲明在那裏(因爲它會迫使我每次改變它在Customer類的任何變化。

有沒有什麼辦法:

  • 「動態」基礎上建立的searchList字典,從而消除了switch結構需要查詢?
  • 將各種條件「連接」成單個數據庫查詢?

回答

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); 
+0

感謝您的答案,非常感謝和工作像一個魅力!有沒有簡單的方法來搜索內嵌(List)屬性?沿着'searchList.Add(「CustomerLikes/CustomerLikedObject.Id」,12345)'? – vzwick

+0

@vzwick從來沒有試圖使用動態LINQ嵌套列表,你應該自己驗證這個功能。但它絕對支持嵌套的對象,如'地址。國家' –

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(); 
0

是類型安全!

這是更好地構建的功能列表,將返回的良好性能高於申報,如果有一天你想改變你的列名,將失敗的一個字符串變量:

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()); 
    } 
} 
+0

哈哈@喬恩Skeet參考。 – vzwick