6
\$\begingroup\$

the requirement for our search query is to look for all search words in the beginning of vehicle manufacturer, model and variant name. Case insensitive. The word being a string of characters separated by space.

E.g. when search for "AU A3 TDI" you would find a vehicle with the following attributes: Vehicle { ManufacturerName = "Audi", ModelName = "A3", Name = "2.0L TDI" }

...but would not return this vehicle: Vehicle { ManufacturerName = "Renault", ModelName = "A3", Name = "2.0L TDI" } because no words start with au.

I'm using specification with LINQ Expression and the code I wrote works fine and is tested however I believe it smells a bit. It's not very readable IMHO but most importantly, there might be a clear performance improvement you could point out?

public string[] SearchTerms = searchText.Split();
Expression<Func<SearchVehicleVariant, bool>> expression = 
c =>
SearchTerms.All(
 s =>
 string.Format(
 " {0} {1} {2}",
 c.ManufacturerName != null ? c.ManufacturerName.ToUpper() : string.Empty,
 c.ModelName != null ? c.ModelName.ToUpper() : string.Empty,
 c.Name != null ? c.Name.ToUpper() : string.Empty).Contains(
 string.Concat(" ", s.Trim().ToUpper())));
asked Mar 19, 2013 at 16:46
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Given your requirements, it seems you would be best using String.StartsWith and a StringComparison value which ignores case (i.e., CurrentCultureIgnoreCase, InvariantCultureIgnoreCase, or OrdinalIgnoreCase). This should be a little cleaner and faster than doing case conversions.

Expression<Func<SearchVehicleVariant, bool>> expression = 
 c => SearchTerms.All (
 (c.ManufacturerName ?? string.Empty).StartsWith (s, StringComparison.InvariantCultureIgnoreCase)
 || (c.ModelName ?? string.Empty).StartsWith (s, StringComparison.InvariantCultureIgnoreCase)
 || (c.Name ?? string.Empty).StartsWith (s, StringComparison.InvariantCultureIgnoreCase));
answered Mar 19, 2013 at 18:00
\$\endgroup\$
1
  • \$\begingroup\$ thanks. sorry but this wouldn't fulfil my requirements. The search is done on every word, not just the first word of each of the attributes. I've modified the search criterion in my q to make it clearer. \$\endgroup\$ Commented Mar 20, 2013 at 9:07
1
\$\begingroup\$

I'm not entirely sure how your second example fails to match, because the string "Renault A3 2.0L TDI" contains all of "AU", "A3", and "2.0".

That being said, here's an attempt at a cleaner rewrite:

Expression<Func<SearchVehicleVariant, bool>> expression = 
 c => SearchTerms.Select(s => s.Trim())
 .All(s => 
 TestField(c.ManufacturerName ?? "", s)
 || TestField(c.ModelName ?? "", s)
 || TestField(c.Name ?? "", s)
 );
// Helper function
bool TestField(string field, string test)
{
 return field.Split(' ').Any(x => x.StartsWith(s, StringComparison.InvariantCultureIgnoreCase);
}
answered Mar 19, 2013 at 17:43
\$\endgroup\$
2
  • 1
    \$\begingroup\$ "AU" must be in the beginning of any word in the ManufactuerName || ModelName || Name \$\endgroup\$ Commented Mar 20, 2013 at 9:08
  • \$\begingroup\$ @Chuck - Ah, there could be multiple words in each field? That wasn't clear from your example. Edited. \$\endgroup\$ Commented Mar 20, 2013 at 13:47

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.