ASP.NET MVC: jqGrid и поиск. Refactoring

В прошлой статье мы ознакомились с тем как вывести таблицу используя плагин jqGrid, реализовали постраничный вывод данных и поиск на стороне сервера.

Если приложение не предполагает наличие большого количества таблиц и дальнейшее развитие не предполагается, то на этой реализации можно остановиться. Все просто и наглядно. Но если все не так облачно и требуется предоставить пользователю поиск по моделям с множеством свойств, то реализация этого станет проверкой на прочность. Потому как каждый метод по запросу данных раздуется на то количество полей по которым нужно реализовать поиск. Есть простой способ избавиться от методов с множеством параметров используя стандартную  возможность  биндинга моделей.

В результате рефакторинга метод

 
public JsonResult ProductData(int? page, bool _search, int? productId,             
string productName, string category, string supplier,             
int? unitPrice, int? unitsInStock, string englishName)

станет выглядеть вот так

 
public JsonResult ProductData(int? page, bool _search, Product searchProduct) 

Красиво, не правда ли?

Начнем. Модификация затронет два класса Product и ProductController.

Исходники начального проекта можно взять тут.

Модель Product.

Предварительно изменим модель Product. Так как при поиске передаются только поля имеющие значения, то при биндинге поля значимых типов: int, decimal будут равны 0, а поле типа bool будет равно false. Это создает лишние проблемы при фильтрации данных. Для того чтобы избежать этого нужно воспользоваться Nullable Types и модифицировать модель Product.

Открываем файл Product.cs и используя сокращенный синтаксис записи Nullable типов, меняем поля: ProductId, UnitPrice, UnitsInStock, Discontinued. Результат должен выглядеть так:

     
    public class Product
    {
        public int? ProductId { get; set; }
        public string ProductName { get; set; }
        public string Category { get; set; }
        public string Supplier { get; set; }
        public decimal? UnitPrice { get; set; }
        public short? UnitsInStock { get; set; }
        public string EnglishName { get; set; }
        public bool? Discontinued { get; set; }
    }

Контроллер ProductController

Теперь мы готовы произвести рефакторинг метода ProductData. Первым делом заменяем набор аргументов для поиска по полям на один:

public JsonResult ProductData(int? page, bool _search, Product searchProduct)

Далее воспользуемся searchProduct для получения значений для фильтра данных.

            if (_search)
            {
                if (null != searchProduct.ProductId)
                    list = list.Where(x => searchProduct.ProductId == x.ProductId);

                if (!String.IsNullOrEmpty(searchProduct.ProductName))
                    list = list.Where(x => searchProduct.ProductName == x.ProductName);

                if (!String.IsNullOrEmpty(searchProduct.Category))
                    list = list.Where(x => searchProduct.Category == x.Category);

                if (!String.IsNullOrEmpty(searchProduct.Supplier))
                    list = list.Where(x => searchProduct.Supplier == x.Supplier);

                if (null != searchProduct.UnitPrice)
                    list = list.Where(x => searchProduct.UnitPrice == x.UnitPrice);

                if (null != searchProduct.UnitsInStock)
                    list = list.Where(x => searchProduct.UnitsInStock == x.UnitsInStock);

                if (!String.IsNullOrEmpty(searchProduct.EnglishName))
                    list = list.Where(x => searchProduct.EnglishName == x.EnglishName);
            }

Вот и все. Все работает так же, но метод ProductData выглядит на так загроможденно, хотя есть еще над чем поработать.

Исходники итогового проекта.