tags:

views:

104

answers:

3

(The title for this question isn't the best, but I'm unsure how else to word it!)

I'm working on a search form which contains a checklist of values. Basically, a checked item means 'include this type in the search'. Something like this:

Search for item: __________
Search in:
      [ ] Fresh Foods
      [ ] Frozen Foods
      [ ] Beverages
      [ ] Deli Counter

I have an object to represent this search:

class FoodSearchCriteria{
    public string SearchString {get;set;}
    public bool SearchFreshFoods {get;set;}
    public bool SearchFrozenFoods {get;set;}
    public bool SearchBeverages {get;set;}
    public bool SearchDeliCounter {get;set;}
}

The only way I can think of doing this atm is like this:

public IList<FoodItem> FindFoodItems(FoodSearchCriteria criteria)
// in reality, this is a fuzzy search not an exact match
var matches = _DB.FoodItems.Where(x => x.FoodTitle == SearchString);

var inCategories = new List<FoodItem>();

if (criteria.SearchFreshFoods)
   inCategories.Add(matches.Where(x => x.Type == 'Fresh Foods'));
if (criteria.SearchFrozenFoods)
   inCategories.Add(matches.Where(x => x.Type == 'Frozen Foods'));
//etc etc

return inCategories;
}

This feels like a code smell to me, what would be a better way to approach it?

+5  A: 

Take a look at PredicateBuilder

PredicateBuilder predicate = PredicateBuilder.False<FoodItem>();
if (criteria.SearchFreshFoods)
{
    predicate = predicate.Or(x => x.Type == 'Fresh Foods');
}
if (criteria.SearchFrozenFoods)
{
    predicate = predicate.Or(x => x.Type == 'Frozen Foods'));
}
...

_DB.FoodItems.Where(predicate);
Winston Smith
Looks incompleet. pb == predicate?
Dykam
Yes. Apologies, now fixed.
Winston Smith
+3  A: 

Have you tried:

List<string> types = new List<string>();

if (criteria.SearchFreshFoods) { types.Add("Fresh Foods"); }
if (criteria.SearchFrozenFoods) { types.Add("Frozen Foods"); }
if (criteria.SearchBeverages) { types.Add("Beverages"); }
if (criteria.SearchDeliCounter) { types.Add("Deli Counter"); }

return _DB.FoodItems.Where(x => x.FoodTitle == SearchString &&
                                types.Contains(x.Type));

That means just one SQL query, which is handy.

You could certainly refactor the FoodSearchCriteria type to make it easier to build the list though...

Jon Skeet
Feel free to elaborate on what refactoring you have in mind :)
Kirschstein
Not sure off-hand... but at the very least it would make sense to put the code to build the list *into* that class.
Jon Skeet
A: 

I have no time to review but this could be an untested solution.

class SearchItem
{
   string Name {get; set;}
   bool IsSelected {get; set;}
}

class FoodSearchCriteria
{
   String searchText {get; set;}
   IList<SearchItem> SearchItems{ get; }
}

public IList<FoodItem> FindFoodItems(FoodSearchCriteria criteria)
// in reality, this is a fuzzy search not an exact match
var matches = _DB.FoodItems.Where(x => x.FoodTitle == criteria.SearchText && 
                                      criteria.SearchItems.Where(si => si.IsSelected).Contains(i => i.Name == x.Type));

return mathces;
}
yapiskan