tags:

views:

43

answers:

2

Is there any way to refactor this code so that it can omit unnecessary WHEREs and JOINs if the values passed into the function are null (this code works just fine right now if all parameters are passed in)? The "SearchItems" and "ItemDistance" functions are table-level functions for performing fulltext search and distance calculations, respectively.

public IQueryable<ItemSearchResult> Search(string keywords, int? category, float? latitude, float? longitude)
{
    return from item in _db.Items
           join searchItems in _db.SearchItems(keywords)
               on item.ItemId equals searchItems.ItemId
           join itemDistance in _db.ItemDistance(latitude.Value, longitude.Value)
               on item.ItemId equals itemDistance.ItemId
           where item.Category == category.Value
           select new ItemSearchResult()
                      {
                          Item = item,
                          Distance = itemDistance.Distance
                      };
}
+1  A: 

For starters, the only value passed into that function that can be null is keywords, as all others are non-nullable value types. So I'll consider that only (if you need it, others can be treated similarly).

Just don't use joins in the first place:

return from item in _db.Items
       where keywords == null || _db.SearchItems(keywords).Select(si => si.ItemId).Contains(item.ItemId) &&
       ...      
       where item.Category == category
       select new ItemSearchResult()
                  {
                      Item = item,
                      Distance = itemDistance.Distance
                  };
Pavel Minaev
Updated question to have nullable params
Kevin Pang
+2  A: 

I'm making the assumption that if either of latitude or longitude is not provided, you don't calculate the distance (I'd probably encapsulate both into a class and pass that instead of passing separately to avoid confusion). If one or the other is not provided, the default Distance is used for the search result.

public IQueryable<ItemSearchResult> Search(string keywords, int? category, float? latitude, float? longitude)
{
    IEnumerable<ItemSearchResult> result = null;
    var query = _db.Items.AsEnumerable();
    if (category.HasValue)
    {
        query = query.Where( i => i.Category == category.Value );
    }
    if (!string.IsNullOrEmpty(keywords))
    {
        query = query.Where( i => _db.SearchItems(keywords)
                                     .Any( s => s.ItemId == i.ItemId ));
    }
    if (latitude.HasValue && longitude.HasValue)
    {
        result = from item in query
                 join distance in _db.ItemDistance( latitude.Value, longitude.Value )
                     on item.ItemId equals distance.ItemId
                 select new ItemSearchResult
                        {
                            Item = item,
                            Distance = distance.Distance
                        };
    }
    else
    {
         result = query.Select( i => new ItemSearchResult { Item = i } );
    }

    return result != null
              ? result.AsQueryable()
              : new List<ItemSearchResult>().AsQueryable();
}
tvanfosson