2

I've got a pretty straightforward predicate builder query that works well. We have a list of keywords to search on, and we loop through those keywords to see if any of our object properties match up.

var predicateSearchText = PredicateBuilder.False<Asset>();
List<string> separatedKeywords = keywords.Split(',').ToList();

foreach (string s in separatedKeywords)
{
   if (s.Length > 0)
   {
      string temp = s;
      predicateSearchText = predicateSearchText.Or(m => m.Notes.Contains(temp));
      predicateSearchText = predicateSearchText.Or(m => m.Description.Contains(temp));
      predicateSearchText = predicateSearchText.Or(m => m.DetailedDescription.Contains(temp));
      predicateSearchText = predicateSearchText.Or(asset => asset.Keywords.Contains(temp));
      predicateSearchText = predicateSearchText.Or(a => a.AssetFiles.Any(x => x.FileName.Contains(temp)));
   }
}

...down further I do:

var query = (from a in masterQuery.Where(predicateSearchText);

and I get what I need - filter to only those with the keywords for which I've searched.

I need to change this so that I look for ALL of the keywords within a certain property of my entity. so the "notes" field must have each keyword being searched for, OR, the "description" field must have all keywords being searched for. I think this involves inner/outer predicates, but I haven't been able to come up with it. What I've tried gives me too many results, it should only give me one... the other entities don't match the criteria. is my problem obvious? My keywords (6 of them) are very unique, i'm getting back over 600 items instead of the 1...

var predicateSearchText = PredicateBuilder.False<Asset>();
var notesPred = PredicateBuilder.True<Asset>();
var descPred = PredicateBuilder.True<Asset>();
var detdescPred = PredicateBuilder.True<Asset>();
var keywordPred = PredicateBuilder.True<Asset>();
var filesPred = PredicateBuilder.True<Asset>();

foreach (string s in separatedKeywords.Where(xx=>xx.Length > 0))
   descPred.And(m => m.Description.Contains(s));

foreach (string s in separatedKeywords.Where(xx => xx.Length > 0))
   notesPred.And(m => m.Notes.Contains(s));

foreach (string s in separatedKeywords.Where(xx => xx.Length > 0))
   detdescPred.And(m => m.DetailedDescription.Contains(s));

foreach (string s in separatedKeywords.Where(xx => xx.Length > 0))
   keywordPred.And(m => m.Keywords.Contains(s));

foreach (string s in separatedKeywords.Where(xx => xx.Length > 0))
   filesPred.And(a => a.AssetFiles.Any(x => x.FileName.Contains(s)));

predicateSearchText = predicateSearchText.Or(notesPred.Expand());
predicateSearchText = predicateSearchText.Or(descPred.Expand());
predicateSearchText = predicateSearchText.Or(detdescPred.Expand());
predicateSearchText = predicateSearchText.Or(keywordPred.Expand());
predicateSearchText = predicateSearchText.Or(filesPred.Expand());

Then I do my:

var query = (from a in masterQuery.Where(predicateSearchText);

And I get way too many results for the predicate to be correct.

Brian
  • 5,069
  • 7
  • 37
  • 47
TheRedDwarf
  • 183
  • 1
  • 13

1 Answers1

0

I had the same problem today. Move the PredicateBuilder instantiation and Where() function inside of the loop, and it will effectively AND the seperate keyword predicates.

var predicateSearchText;
List<string> separatedKeywords = keywords.Split(',').ToList();

foreach (string s in separatedKeywords)
{
   if (s.Length > 0)
   {
      predicateSearchText = PredicateBuilder.False<Asset>();

      string temp = s;
      predicateSearchText = predicateSearchText.Or(m => m.Notes.Contains(temp));
      predicateSearchText = predicateSearchText.Or(m => m.Description.Contains(temp));
      predicateSearchText = predicateSearchText.Or(m => m.DetailedDescription.Contains(temp));
      predicateSearchText = predicateSearchText.Or(asset => asset.Keywords.Contains(temp));
      predicateSearchText = predicateSearchText.Or(a => a.AssetFiles.Any(x => x.FileName.Contains(temp)));

      Query = Query.AsExpandable().Where(predicateSearchText);
   }
}
Tom Halladay
  • 5,651
  • 6
  • 46
  • 65