Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Implementing Search Without Convoluted If Statements In ASP.NET MVC

4.67/5 (5 votes)
15 Feb 2016CPOL2 min read 12.3K  
Implementing search without convoluted If statements in ASP.NET MVC

Implementing Search Without Convoluted If Statements In Asp.Net MVC

Introduction

In the beginning, when I start to learn C# and ASP.NET MVC, building search form was a complicated thing to do for me, the more criteria I've had for a search form, the harder it would get, but it was hard because I didn't use the proper tools to do my job, back then, I didn't know about IQueryable interface and what Linq deferred execution was. In this post, I'm going to show you how you can build any kind of search form without complicating things, using Linq deferred execution.

Search Form, The Wrong Way

First, I'm going to show you the wrong way to do it, and I'm telling you, if your search becomes more than a mere two field, the logic can become a real mess, Imagine we have a search form like this:

Image 1

And here our ugly, naive, mess of code for this form:

JavaScript
public ActionResult ManageOrders
(DateTime fromDate, DateTime toDate, string tracingCode, string customerName)
        {
            if (!string.IsNullOrEmpty(fromDate) && !string.IsNullOrEmpty(toDate) 
            && string.IsNullOrEmpty(tracingCode) && string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.OrderDate >= fromDate && s.OrderDate <= toDate);
                return View(model);
            }
            else if (!string.IsNullOrEmpty(fromDate) && !string.IsNullOrEmpty(toDate) 
            && !string.IsNullOrEmpty(tracingCode) && !string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.OrderDate >= fromDate 
                && s.OrderDate <= toDate 
                && s.TracingCode == tracingCode && s.CustomerName == customerName);
                return View(model);
            }
            else if (!string.IsNullOrEmpty(fromDate) && !string.IsNullOrEmpty(toDate) 
            && string.IsNullOrEmpty(tracingCode) && !string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.OrderDate >= fromDate 
                && s.OrderDate <= toDate && s.CustomerName == customerName);
                return View(model);
            }
            else if (!string.IsNullOrEmpty(fromDate) && !string.IsNullOrEmpty(toDate) 
            && !string.IsNullOrEmpty(tracingCode) && string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.OrderDate >= fromDate 
                && s.OrderDate <= toDate && s.TracingCode == tracingCode);
                return View(model);
            }
            else if (string.IsNullOrEmpty(fromDate) && string.IsNullOrEmpty(toDate) 
            && !string.IsNullOrEmpty(tracingCode) && !string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.TracingCode == tracingCode 
                && s.CustomerName == customerName);
                return View(model);
            }
            else if (string.IsNullOrEmpty(fromDate) && string.IsNullOrEmpty(toDate) 
            && string.IsNullOrEmpty(tracingCode) && !string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.CustomerName == customerName);
                return View(model);
            }
            else if (string.IsNullOrEmpty(fromDate) && string.IsNullOrEmpty(toDate) 
            && !string.IsNullOrEmpty(tracingCode) && string.IsNullOrEmpty(customerName))
            {
                var model = db.Orders.Where(s => s.TracingCode == tracingCode);
                return View(model);
            }

            return View(db.Orders);            
	    }

As you can see, we have to check for each and every one of the conditions, for when one field is filled and others are empty and vise versa, and return the correct filtered model, this approach is just plain wrong and shouldn't be used, at least when we have Linq and deferred execution.

Search From, The Right Way

With the powers that Linq and its deferred execution give us, we turn the above code to this:

JavaScript
public ActionResult ManageOrders
(DateTime fromDate, DateTime toDate, string tracingCode, string customerName)
        {
            IQueryable<orders> orders = db.Orders;

            if (!string.IsNullOrEmpty(fromDate) && !string.IsNullOrEmpty(toDate))
            {
                orders = orders.Where(s => s.OrderDate >= startDate && s.OrderDate <= endDate);
            }

            if (!string.IsNullOrEmpty(tracingCode))
            {
                orders = orders.Where(s => s.TracingCode.Contains(tracingCode));
            }

            if (!string.IsNullOrEmpty(customerName))
            {
                orders = orders.Where(s => s.CustomerName.Contains(customerName));
            }
			
            return View(orders);
	    }</orders>

You can make it even shorter if you use ternary if, but the point is, now all we had to do was to check if the action parameter is not empty, and add another where to our search query. Here, we use Linq to SQL which is different form Linq to object, but we can use Linq to object too, which means we can use IEnumerable instead of IQueryable, but using IQueryable here is more efficient, here is a good explanation of their difference, to put it briefly, Linq to SQL runs our query in the SQL Server, so we get only what we need, but Linq to object retrieves the whole entity and then filters it in memory.

With deferred execution that Linq gives us, we can build an IQueryable or IEnumerable and accumulate our wheres on it based on our conditions, this is far better than what we had before.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)