Рефакторинг метода фильтрации данных C#
Я создаю метод для получения данных и могу отфильтровать выборку по двум полям: Code и Value. Оба этих поля могут быть null (в таком случае мне не нужно фильтровать их вообще) и из-за этого я столкнулся с проблемой масштабирования подобного решения.
Ниже привожу свой код который работает как надо и верно выдаёт данные. Вопрос вот в чём: нормален ли тот факт, что при добавления новых фильтров по новым полям мне придётся расширять класс handler и вообще иметь кучу проверок? Как я могу от этого избавиться? какие best practices есть на этот счёт?
Класс обработчика запроса:
public async Task<IEnumerable<Product>> Handle(GetProductsQuery query, CancellationToken cancellationToken)
{
var filters = new List<Expression<Func<Product, bool>>>();
if (query.Code.HasValue) filters.Add(p => p.Code == query.Code);
if (!string.IsNullOrEmpty(query.Value)) filters.Add(p => p.Value == query.Value);
var products = await _productRepository.GetAll(filters);
return products;
}
Класс репозитория, который обращается к базе:
public async Task<IEnumerable<Product>> GetAll(IEnumerable<Expression<Func<Product, bool>>> filters)
{
IQueryable<Product> products = _context.Products;
if (filters != null)
{
foreach (var filter in filters)
{
products = products.Where(filter);
}
}
return await products.ToListAsync();
}
Ответы (1 шт):
Ну здесь в целом всё нормально. Единственное, что я бы оптимизировал, это выбросил бы машину состояний, так как await один и в самом конце метода.
public Task<IEnumerable<Product>> Handle(GetProductsQuery query, CancellationToken cancellationToken)
{
var filters = new List<Expression<Func<Product, bool>>>();
if (query.Code.HasValue)
filters.Add(p => p.Code == query.Code);
if (!string.IsNullOrEmpty(query.Value))
filters.Add(p => p.Value == query.Value);
return _productRepository.GetAll(filters);
}
public Task<IEnumerable<Product>> GetAll(IEnumerable<Expression<Func<Product, bool>>> filters)
{
IQueryable<Product> products = _context.Products;
foreach (var filter in filters)
{
products = products.Where(filter);
}
return products.ToListAsync();
}
Проверка filters на null тоже лишняя, исходя из логики вызывающего метода.
Избавиться от перечисления свойств не просто, можно попробовать через рефлексию.
var props = typeof(GetProductsQuery).GetProperties();
foreach (PropertyInfo pi in props)
{
// здесь проверка на Value/Reference type
// далее на 0/null и т.д. для всех поддерживаемых типов полей.
}
Но я не уверен, что так стоит делать и возможно для того чтобы EF это скушал, придется динамически строить Expression. В общем, копать куда-то туда, но советую заниматься этим не раньше, чем появится реальная потребность.