Одним из улучшений было бы создание функции, которая делает то, что вы хотите.
Кажется, что у вас есть входная последовательность Products
, и вы хотите отфильтровать эту входную последовательность, чтобы сохранить только те Products
, которые соответствуют некоторому предикату.
Вы не очень заинтересованыв создании Expression
.В конце концов, этот Expression
будет использоваться только в операторе Where
для получения подмножества Products
.
Итак, прежде всего: вам нужно создать функцию, которая вместо этого возвращает IQueryable<Product>
Expression<Product>
.
Мы напишем его как функцию расширения Product
.См. Расширение методов расширения:
static class ProductExtensions
{
public static IQueryable<Product> Filter(this IQueryable<Product> products,
Filter filter)
{
// TODO: implement
}
}
Использование будет:
using (var dbContext = new MyDbContext())
{
Filter filter = ReadFilterComboBoxes();
var result = dbContext.Products.Filter(filter);
}
При желании вы можете использовать это как любую другую функцию LINQ:
var result = dbContext.Products.Where(product => ...)
.Filter(productFilter)
.Select(product => )
.GroupBy(...);
Очевидно, у вас есть класс Filter
, который содержит значения свойств, которые будут использоваться в качестве предиката в Where
в вашем запросе.Но почему-то вы хотите сказать: «не используйте это свойство в фильтре, потому что оператор не выбрал никакого значения в поле со списком»
Чтобы указать, что оператор не выбрал какое-либо значение,Вы можете использовать NULL.Для этого вам нужно сделать свойства обнуляемыми.См. , как использовать обнуляемые значения
Классы всегда обнуляются.Вы делаете тип значения (int, double, structs, enums) обнуляемым, добавляя знак вопроса к типу:
class Filter
{
public int? ProductId {get; set;}
public int? LocationId {get; set;}
...
}
Теперь вы можете сказать, что свойство не должно использоваться, потому что оператор не сделалвыберите значение в поле со списком, присвоив ему значение NULL:
Filter selectedFilter = new Filter()
{
ProductId = null; // operator didn't select the userId combo
LocationId = LocationCombo.SelectedValue;
...
}
В зависимости от типа используемых полей со списком, SelectedValue может уже иметь значение NULL, если ничего не выбрано, в противном случае вы должны проверитьсебя:
ProductId = ProductCombo.IsValueSelected ?? ProductCombo.Value : null;
Теперь, когда вы изменили класс Filter
, легко реализовать метод Filter
public static IQueryable<Product> Filter(this IQueryable<Product> products, Filter filter)
{
// TODO: exception if products == null
if (filter == null)
{
// don't filter, return the original collection:
return products;
}
else
{
return products.Where (product =>
(filter.ProductId == null || filter.ProductId == product.ProductId)
&& (filter.LocationId == null || filter.LocationId == product.LocationId)
&& ...);
}
}
}