【问题标题】:Filtered tokenised search result with Linq and EF使用 Linq 和 EF 过滤的标记化搜索结果
【发布时间】:2011-10-24 06:25:21
【问题描述】:

我正在寻找一种方法来创建基于标记化查询字符串的过滤系统以返回农场列表。

希望过滤机制足够灵活,让我可以按任何顺序提供令牌以返回结果。

搜索规则如下:

州:西澳作物:香蕉

会给我一个过滤列表,列出WA 中所有农场的列表,作物为banana

作物:香蕉州:WA

应该返回相同的结果。

城市:奥尔巴尼作物:香蕉

会给我一个过滤列表,列出Albany 中所有农场的列表,作物为banana

提供的每个值都可以用引号引起来,以允许对空格分隔的值进行分组。例如

城市:“巴克山”作物:香蕉

会给我一个过滤列表,列出Mount Barker 的所有农场,作物为banana

此外,任何非标记化查询都只会在农场Details 属性内查找,以再次返回农场列表,并用引号组合多个单词查询。

---------------------------编辑------- --------------------------------------

我当前使用谓词的搜索系统编码如下。很长(抱歉),这是我的第一次尝试,但我希望这可以被某个善良的灵魂重构。

非常感谢:

    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);
        }
    }

【问题讨论】:

    标签: asp.net-mvc linq c#-4.0 entity-framework-4


    【解决方案1】:

    只是猜测,如果引入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;
    

    【讨论】:

    • 我实际上用我的 !StringIsNullOrWhitespace 调用解决了这个问题,但忘记更新代码注释。我会看看你的建议,因为它看起来更干净。我想我真的很想看看我现在是否在做任何愚蠢的事情......谢谢!
    • 哦,Details 是一个字符串吗?如果是这样,我的建议将不正确。我认为这是某种集合(列表)。
    • 是的,它是....抱歉,如果不清楚。我刚刚在 predicate.Or 语句中工作时遇到了麻烦。出于某种原因,当我使用它们时,所有农场都会被退回。
    • @James 好的,我会删除我的答案(如果可以的话),因为这对您的问题没有任何帮助。抱歉打扰了。
    • 一点也不......任何兴趣都是好的!实际上,一旦我整理完代码,我就会发布一些代码,因为看起来我已经完成了大部分工作。
    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    相关资源
    最近更新 更多