суббота, 7 ноября 2009 г.

LINQ dynamic expressions. WHERE <T> IN <Filters>. Part2 - Improvements

В предыдущей статье мы рассмотрели как можно создать аналог SQL опператора WHERE IN.
В результате мы получили LINQ выражение в вид:

string[] filters = new [] { "WA", "SP", "BC" };
var customers = context.Customers.In(p => p.Region, filters);

В читабильности мы не достигли идеального результат, но Restuta предложил решение, как можно его улучшить.

Благодарности:
     Спасибо Restuta за предложенное улучшение.

Рассмотри что изменилось.

Для начала, нам необходимо создать вспомогательный класс, который, как сказал Restuta, надо "пропихнуть"... Наш класс будет выглядеть так:

public class QueryableProperty<T, TKey>
{
     /// <summary>Gets or sets the original query.</summary>
     /// <value>The query.</value>
     public IQueryable<T> Query { get; set; }

     /// <summary>Gets or sets the column to filter.</summary>
     /// <value>The column.</value>
     public Expression<Func<T, TKey>> Column { get; set; }
}

Затем нам необходим вспомогательный Extenstion Method, который как раз и будет "пропихивать" поле, которое мы хотим фильтровать и оригинальный запрос. Этот Extenstion Method как раз и является тем самым улучшением, который придает желаемой читабельности.

/// <summary>Aggregates property for future WHERE IN clause.</summary>
/// <typeparam name="T">The result entity type.</typeparam>
/// <typeparam name="TKey">The type of column to filter.</typeparam>
/// <param name="query" />The original query.</param>
/// <param name="column" />The column to filter.</param>
public static QueryableProperty<T, TKey> WhereProperty<T, TKey>(this IQueryable<T> query, Expression<Func<T, TKey>> column)
{
     return new QueryableProperty<T, TKey> { Query = query, Column = column };
}

Extenstion Method 'IN' почти не изменился, я не буду приводить его код, покажу только сигнатуру, по которой все станет ясно.

public static IQueryable<T> In<T, TKey>(this QueryableProperty<T, TKey> queryableProperty, IEnumerable<TKey> filters)

В результате, наше вырежание приняло следующий вид:

string[] filters = new [] { "WA", "SP", "BC" };
var customers = context.Customers
     .WhereProperty(p => p.Region)
     .In(filters)
     .OrderBy(p => p.Region);

Получилось гламурненько. Как вы видите, цепочка вызовов не прерывается. Это самое главное. После In мы опять возвращаем IQueryable<T> и можем продолжать использовать другие Extension Methods.
Мы, конечно, можем обратиться к оригинальному запросу и после WhereProperty через свойство Query, но WhereProperty предназначался не для того.

Мы добились желаемого результат \m/

1 комментарий:

  1. " как сказал Restuta, надо "пропихнуть" "
    =))), Как говорится - спасибо за благодарность =)

    ОтветитьУдалить