patterncsharpMinor
Search for variants of keywords using LINQ
Viewed 0 times
linqsearchvariantsusingkeywordsfor
Problem
First, I'm adding words entered into a search field to an array. Then, I'm getting results from a stored procedure on SQL Server using Database First approach with Entity Framework.
Finally, for each word in the array, I'm filtering the results using this query:
```
products = products.Where(item => (item.basedescription.ToLower().StartsWith(searchWords[x] + " ")
|| item.basedescription.ToLower().StartsWith(service.Pluralize(searchWords[x]) + " ")
|| item.basedescription.ToLower().StartsWith(service.Singularize(searchWords[x]) + " ")
|| item.basedescription.ToLower().EndsWith(" " + searchWords[x])
|| item.basedescription.ToLower().EndsWith(" " + service.Pluralize(searchWords[x]))
|| item.basedescription.ToLower().EndsWith(" " + service.Singularize(searchWords[x]))
|| item.basedescription.ToLower().Contains(" " + searchWords[x] + " ")
|| item.basedescription.ToLower().Contains(" " + service.Pluralize(searchWords[x]) + " ")
|| item.basedescription.ToLower().Contains(" " + service.Singularize(searchWords[x]) + " ")
|| item.basedescription.ToLower().Contains(searchWords[x])
|| item.basedescription.ToLower().Contains(service.Pluralize(searchWords[x]))
|| item.basedescription.ToLower().Contains(service.Singularize(searchWords[x])))
|| (item.info.ToLower().StartsWith(searchWords[x] + " ")
|| item.info.ToLower().StartsWith(service.Pluralize(searchWords[x]) + " ")
|| item.info.ToLower().StartsWith(service.Singularize(searchWords[x]) + " ")
|| item.info.ToLower().EndsWith(" " + searchWords[x])
|| item.info.ToLower().EndsWith(" " + service.Pluralize(searchWords[x]))
|| item.info.ToLower().EndsWith(" " + service.Singularize
Finally, for each word in the array, I'm filtering the results using this query:
```
products = products.Where(item => (item.basedescription.ToLower().StartsWith(searchWords[x] + " ")
|| item.basedescription.ToLower().StartsWith(service.Pluralize(searchWords[x]) + " ")
|| item.basedescription.ToLower().StartsWith(service.Singularize(searchWords[x]) + " ")
|| item.basedescription.ToLower().EndsWith(" " + searchWords[x])
|| item.basedescription.ToLower().EndsWith(" " + service.Pluralize(searchWords[x]))
|| item.basedescription.ToLower().EndsWith(" " + service.Singularize(searchWords[x]))
|| item.basedescription.ToLower().Contains(" " + searchWords[x] + " ")
|| item.basedescription.ToLower().Contains(" " + service.Pluralize(searchWords[x]) + " ")
|| item.basedescription.ToLower().Contains(" " + service.Singularize(searchWords[x]) + " ")
|| item.basedescription.ToLower().Contains(searchWords[x])
|| item.basedescription.ToLower().Contains(service.Pluralize(searchWords[x]))
|| item.basedescription.ToLower().Contains(service.Singularize(searchWords[x])))
|| (item.info.ToLower().StartsWith(searchWords[x] + " ")
|| item.info.ToLower().StartsWith(service.Pluralize(searchWords[x]) + " ")
|| item.info.ToLower().StartsWith(service.Singularize(searchWords[x]) + " ")
|| item.info.ToLower().EndsWith(" " + searchWords[x])
|| item.info.ToLower().EndsWith(" " + service.Pluralize(searchWords[x]))
|| item.info.ToLower().EndsWith(" " + service.Singularize
Solution
It seems weird or unusual that you're assigning
That said, this is one such case where the query syntax has an advantage over the method syntax - be it only to reduce the repetition by leveraging the
The
If
Consider extracting each "group" of conditions into their own, well-named, private function.
Remember that in C#, member names should be
The final code could look like this:
Where
string.ToLower() and string.ToLowerInvariant() is probably a relevant read, too... as would be How can I do a case insensitive string comparison.
products from products. products is your IQueryable source, and the result of the query is some List.That said, this is one such case where the query syntax has an advantage over the method syntax - be it only to reduce the repetition by leveraging the
let keyword and caching the service method calls' return values instead of re-computing them for every single comparison, for every single item in your source:var value = searchWords[x];
var pluralized = service.Pluralize(value);
var singularized = service.Singularized(value);
var result = (from product in products
let description = product.basedescription.ToLower()
let info = product.info.ToLower()
let itemGroup = product.itemgroup
where description.StartsWith(pluralized)
|| description.StartsWith(singularized)
|| ...
|| info.StartsWith(pluralized)
|| info.StartsWith(singularized)
|| ...
|| itemGroup.StartsWith(pluralized)
|| itemGroup.StartsWith(singularized)
|| ...
).ToList();The
|| operator is short-circuiting, so the whole expression is true as soon as one condition is true - by putting the .Contains checks first, the .StartsWith and .EndsWith checks would only be executed when .Contains is false... but then, these checks are redundant:- If
.Contains(value)is true...
.Contains(" " + value + " ")is true.
.StartsWith(value)is also true.
.EndsWith(value)is true as well.
If
.Contains(value) is false, then all of the above are false as well.Consider extracting each "group" of conditions into their own, well-named, private function.
Remember that in C#, member names should be
PascalCase, so basedescription should be BaseDescription, for example.The final code could look like this:
var value = searchWords[x];
var pluralized = service.Pluralize(value);
var singularized = service.Singularized(value);
var result = (from product in products
let description = product.basedescription.ToLower()
let info = product.info.ToLower()
let itemGroup = product.itemgroup.ToLower()
where IsFound(value, description, pluralized, singularized)
|| IsFound(value, info, pluralized, singularized)
|| IsFound(value, itemGroup, pluralized, singularized)
).ToList();Where
IsFound is a little function that matches a Func delegate.string.ToLower() and string.ToLowerInvariant() is probably a relevant read, too... as would be How can I do a case insensitive string comparison.
Code Snippets
var value = searchWords[x];
var pluralized = service.Pluralize(value);
var singularized = service.Singularized(value);
var result = (from product in products
let description = product.basedescription.ToLower()
let info = product.info.ToLower()
let itemGroup = product.itemgroup
where description.StartsWith(pluralized)
|| description.StartsWith(singularized)
|| ...
|| info.StartsWith(pluralized)
|| info.StartsWith(singularized)
|| ...
|| itemGroup.StartsWith(pluralized)
|| itemGroup.StartsWith(singularized)
|| ...
).ToList();var value = searchWords[x];
var pluralized = service.Pluralize(value);
var singularized = service.Singularized(value);
var result = (from product in products
let description = product.basedescription.ToLower()
let info = product.info.ToLower()
let itemGroup = product.itemgroup.ToLower()
where IsFound(value, description, pluralized, singularized)
|| IsFound(value, info, pluralized, singularized)
|| IsFound(value, itemGroup, pluralized, singularized)
).ToList();Context
StackExchange Code Review Q#140248, answer score: 4
Revisions (0)
No revisions yet.