Search code examples
c#linqentity-frameworkasp.net-mvc-4viewdata

How do I write an MVC Entity Framework select query from the controller using passed string arguments?


I created a search tool in MVC. The user types the searchTerm string into a search box and selects options for the search from 2 dropdown select lists. From the first list the user selects "Fuzzy" or "Literal" for the searchType, and from the second list the user can select a specific field to search, specField. The 3 string values are passed to the controller once the search button is clicked.
I am trying to write an "if" statement that queries the Entity Framework DB model based on these 3 string values passed into the controller. How do I write queries that use these values? This is what I have. I know the queries aren't written correctly:

 Public PartialViewResult _Search(string searchTerm, string specField, string searchType)
 {
      //This works to populate the table with the entire DB 
      _db = new IntegrationDBEntities();
      var request = (from r in _db.Requests
                     select r).ToList();

     //These two are not correct and I need help writing these
     if (searchType == "Fuzzy" && searchTerm != "" && specField != "None")
     {
          request = (from r in _db.Requests
                          where r.(specField).Contains(searchTerm)
                          select r).ToList();
     }
     if (searchType == "Literal" && searchTerm != "" && specField == "None")
     {
          request = (from r in _db.Requests
                         where r.Equals(searchTerm)
                         select r).ToList();
     }
     ViewData.Model = request;
     Return partialView();
 }  

Solution

  • I am not 100% sure about how you Request object looks like, but I would use PredicateBuilder. Here is an example of what your search function could look like.

    IQueryable<Request> SearchRequests (string searchTerm, string specField, string searchType)
    {
        var predicate = PredicateBuilder.False<Request>();
    
        //These two are not correct and I need help writing these
        if (searchType == "Fuzzy" && searchTerm != "" && specField != "None")
        {
            predicate = predicate.Or (r => r.(specField).Contains(searchTerm));
        }
        if (searchType == "Literal" && searchTerm != "" && specField == "None")
        {
            predicate = predicate.Or (r => r.Equals(searchTerm));
        }
    
        return new IntegrationDBEntities()
                      .Requests
                      .AsExpandable()
                      .Where(predicate);
    }
    

    Then your method could look like this:

    Public PartialViewResult _Search(string searchTerm, string specField, string searchType)
     {
         ViewData.Model = SearchRequests(searchTerm, specField, searchType).ToList();
         Return partialView();
     } 
    

    UPDATE: I added working example from LinqPad. You will need to modify it slightly to get it to work for you with EntityFramework.

    void Main()
    {
        var results = SearchRequests("Fuzzy", "later").ToList();
        results.Dump();
    
        var results2 = SearchRequests("Literal", "Test me now").ToList();
        results2.Dump();
    }
    
    // Define other methods and classes here
    public class Request
    {
        public int Id {get;set;}
        public string SearchTerm {get;set;}
    }
    
    public IQueryable<Request> LoadData()
    {
        var list = new List<Request>();
        list.Add(new Request {Id = 1, SearchTerm = "Test me now"});
        list.Add(new Request {Id = 2, SearchTerm = "Test me later"});
        list.Add(new Request {Id = 3, SearchTerm = "Test me maybe"});
        list.Add(new Request {Id = 4, SearchTerm = "Test me now"});
        list.Add(new Request {Id = 5, SearchTerm = "Test me later or never"});
        list.Add(new Request {Id = 6, SearchTerm = "Test me maybe or today"});
    
        return list.AsQueryable();
    }
    
    public IQueryable<Request> SearchRequests (string searchType, string searchTerm)
    {
        var data = LoadData();
        var predicate = PredicateBuilder.False<Request>();
        //These two are not correct and I need help writing these
        if (searchType == "Fuzzy")
        {
            predicate = predicate.Or(r => r.SearchTerm.Contains(searchTerm));
        }
        if (searchType == "Literal")
        {
            predicate = predicate.Or (r => r.SearchTerm.Equals(searchTerm));
        }
    
        return data.Where(predicate);
    }
    
    public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
        public static Expression<Func<T, bool>> False<T> () { return f => false; }
    
        public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
            return Expression.Lambda<Func<T, bool>>
                (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
        }
    
        public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
            return Expression.Lambda<Func<T, bool>>
                (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
        }
    }
    

    Results for first search:

    Id  SearchTerm
    2   Test me later
    5   Test me later or never
    

    Results for second search:

    Id  SearchTerm
    1   Test me now
    4   Test me now