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と後での交差が明らかに曖昧であるという事実を除けば、私はむしろそのステートメントをそこに入れたくありません(クラスswitch内の何かが変更されるたびにそれを変更する必要があるためです。Customer

次の方法はありますか?

  • searchList辞書に基づいて「動的に」クエリを作成し、それによってswitch構成の必要性を排除しますか?
  • さまざまな条件を単一のデータベースクエリに「連結」しますか?
4

3 に答える 3

1

DynamicLINQを使用できます

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);
于 2012-10-30T10:33:36.940 に答える
1

2番目のポイントについては、次のことができます。

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();
于 2012-10-30T10:35:05.907 に答える
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());
    }
}
于 2012-10-30T10:48:15.157 に答える