我正在寻找一种基于标记化查询字符串创建过滤系统的方法,以返回农场列表。
过滤机制有望足够灵活,我可以按任何顺序提供令牌以返回结果。
搜索规则如下:
州:WA作物:香蕉
会为我提供WA
中banana
所有农场的过滤列表。
作物:香蕉州:WA
应该返回相同的结果。
城市:奥尔巴尼作物:香蕉
会为我提供Albany
中banana
所有农场的过滤列表。
提供的每个值都可以用引号括起来,以便对空格分隔值进行分组。 e.g
城市:“巴克山”作物:香蕉
会为我提供Mount Barker
中banana
所有农场的过滤列表。
此外,任何非标记化查询都只会在服务器Details
属性中查找,并使用引号组合多个单词查询再次返回服务器列表。
--------------------------------------- EDIT ------- -------------------------------------
我当前使用谓词的搜索系统编码如下。这很长(抱歉),这是我的第一次尝试,虽然我希望这可以被某种灵魂重构。
非常感谢提前:
public ActionResult Search(string query, int? page)
{
IQueryable<Farm> farms = this.ReadOnlySession.All<Farm>();
if (!String.IsNullOrWhiteSpace(query))
{
// http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder
var predicate = PredicateBuilder.True<Farm>();
// We want to replace the spaces in quoted values here so we can split by space later.
// http://stackoverflow.com/questions/2148587/regex-quoted-string-with-escaped-quotes-in-c
Regex quoted = new Regex(@"""[^""\\]*(?:\\.[^""\\]*)*""");
foreach (var match in quoted.Matches(query))
{
query = query.Replace(match.ToString(), match.ToString().Replace(' ', '-'));
}
// Tidy up the query to remove "".
string[] splitQuery = HttpUtility.UrlDecode(query).Replace("\"", "").Split(' ');
Dictionary<string, string> tokenDictionary = new Dictionary<string, string>();
// Loop through our string[] and create a dictionary. Guids used to allow multiple keys
// of the same value.
Parallel.ForEach(splitQuery, subQuery =>
{
string[] tempArray = subQuery.Split(':');
if (tempArray.Length == 2)
{
tokenDictionary.Add(String.Format("{0}:{1}", tempArray[0], Guid.NewGuid()), tempArray[1]);
}
else
{
tokenDictionary.Add(String.Format("description:{0}", Guid.NewGuid()), subQuery);
}
});
// Loop through the dictionary and create our predicate.
foreach (KeyValuePair<string, string> item in tokenDictionary)
{
string value = item.Value.Replace('-', ' ');
string key = item.Key.Split(':')[0].ToUpperInvariant();
switch (key)
{
case "CROP":
value = Utilities.CreateSlug(value, OzFarmGuideConfig.RemoveDiacritics);
predicate = predicate.And(x => x.Crops.Any(y => value.Equals(y.Slug, StringComparison.OrdinalIgnoreCase)));
break;
case "STATE":
predicate = predicate.And(x => value.Equals(x.City.State.Name, StringComparison.OrdinalIgnoreCase));
break;
case "CITY":
value = Utilities.CreateSlug(value, OzFarmGuideConfig.RemoveDiacritics);
predicate = predicate.And(x => value.Equals(x.City.Slug, StringComparison.OrdinalIgnoreCase));
break;
default:
predicate = predicate.And(x => !String.IsNullOrWhiteSpace(x.Details) && x.Details.Contains(value));
break;
}
}
farms = farms.Where(predicate).OrderByDescending(x => x.Rating)
.ThenByDescending(x => x.RatingVotes);
PagedList<Farm> pagedFarms = new PagedList<Farm>(farms, page.HasValue ? page.Value - 1 : 0, 5);
return View(pagedFarms);
}
else
{
PagedList<Farm> pagedFarms = null;
return View(pagedFarms);
}
}
答案 0 :(得分:0)
只是一个猜测,问题会因引入DefaultIfEmpty()
?
default:
// This is not working at the mo. Getting a null exception when we try
// to initialise PagedList.
predicate = predicate.And(x => x.Details.DefaultIfEmpty().Contains(value));
break;