Skip to content
Leonid Gordo edited this page May 6, 2012 · 1 revision

LINQ Extensions

The MvcBlanketLib adds new LINQ extension methods overloads to simplify tasks of filtering and sorting data. These extension methods overloads include:

  • Where
  • OrderBy

##Where extension method overloads

This new overload is defined in MvcBlanketLib.PageFilters namespace and is designed to simplify tasks of filtering data requested from the storage.

Let's assume we have the table that contains two columns we want to be able to filter onto.

CREATE TABLE Product 
(
  ProductId uniqueidentifier NOT NULL PRIMARY KEY,
  Title nvarchar(max) NOT NULL,
  Price int NOT NULL
)

We want to be able to filter products by Title and Price columns, so we render onto the HTML page two text boxes, so user can enter required conditions into them. In classic approach we could use switch case construct to compose something like that:

public IQueryable<Product> GetProducts(string title, int? price)
{
   IQueryable<Product> products = Context.Products;
   if (!string.IsNullOrWhiteSpace(title))
   {
      products = products.Where(p => p.Title.StartsWith(title));
   }
   if (price != null)
   {
      products = products.Where(p => p.Price < price.Value);
   }
   return products;
}

This approach is not clear to read and is hard to code is case if the number of filters is more than 2 or 3. In addition we have to explicitly define the type of variable products - IQueryable<>, because var statement will cause compile error here as compiler will infer wrong type - DbSet<> that cannot be used in the following LINQ expressions.

We could improve the situation above by using PageFilter<> introduced with MvcBlanket. So we rewrite the example above:

public IQueryable<Product> GetProducts(ProductFiltersModel filters)
{
   IQueryable<Product> products = Context.Products;
   if (filters.Title.Selected)
   {
      products = products.Where(p => p.Title.StartsWith(filters.Title.Value));
   }
   if (filters.Price.Selected)
   {
      products = products.Where(p => p.Price < filters.Price.Value);
   }
   return products;
}

That's a much better because PageFilter<> automatically provides support of Selected property that allows to verify against the exact filter is really used and contains valid data. But to really simplify the code above we can use the new overload of Where extension method:

public IQueryable<Product> GetProducts(ProductFiltersModel filters)
{
   return Context.Products
          .Where(filters.Title, p => p.Title.StartsWith(filters.Title.Value))
          .Where(filters.Price, p => p.Price < filters.Price.Value);       
}

The Where method contains additional PageFilter<> parameter that allows the method to check if filter is selected and conditionally apply predicate given in the second parameter to the IQueryable expression.

##OrderBy extension method overloads

This overload is defined in MvcBlanketLib.Extensions namespace and extends MvcContrib OrderBy implementation that allows to define ColumnName and OrderDirection as string and enumeration member accordingly without lambda expressions. But MvcContrib implementation does not allow to process consequent sortings by several columns at once, so MvcBlanket fills this gap.

The declaration of method looks like:

public static IQueryable<T> OrderBy<T>(
    this IQueryable<T> datasource, 
    string propertyName, 
    SortDirection direction, 
    bool first
)

Additional first parameter allows to specify either this sort is really first so it will be translated into OrderBy|OrderByDescending method or not so it will be translated into ThenBy|ThenByDescending method.

This extension is affectively used in PagedViewModel implementation allowing to sort by multiple columns at once.

Clone this wiki locally