【问题标题】:How to search in subcategories by giving a 'head' category in MVC4如何通过在 MVC4 中给出“头部”类别来搜索子类别
【发布时间】:2014-01-30 20:58:32
【问题描述】:

我正在尝试向我的网站添加一个搜索引擎,您可以在其中通过选择一个类别来搜索产品。类别树的架构如下:

  • HeadCategory1
    • 子类别 1
      • SubSubCategory1
      • SubSubCategory2
    • 子类别2
  • HeadCategory2
    • 子类别3
  • HeadCategory3

在搜索表单中,您只能从 HeadCategories(从数据库中提取)中进行选择。 如何创建一个(递归)函数,在您选择的 HeadCategory 中以及该 headcategory 的子类别和子子类别中进行搜索?

我的搜索代码如下所示:

[HttpPost]
    public ActionResult Search(SearchCriteria model, int? page)
    {
        UnitOfWork _uow = new UnitOfWork();

        int pageNumber = page ?? 1;

        var query = _uow.ProductRepository.Get(
            includeProperties: "Author"
        );

        // Search terms
        string[] keywords = new string[1];
        if (model.Keywords != null && model.Keywords.Length > 0 && model.Keywords.Contains(' '))
            keywords = model.Keywords.Split(' ');
        else
            keywords[0] = model.Keywords;

        if (keywords[0] != null)
        {
            foreach (string word in keywords)
            {
                query = query.Where(p => p.Description.Contains(word) || p.Name.Contains(word));
            }
        }

        if (model.CategoryId > 0 && query.Count() > 0)
        {
            // HERE IS WHERE THE CHANGES SHOULD BE MADE
            query = query.Where(r => r.CategoryId == model.CategoryId);
        }

        List<Product> zipResults = query.ToList();
        RangeResult[] postcodes;
        int postcode;
        if (model.Distance > 0 && int.TryParse(model.Zipcode.Substring(0, 4), out postcode))
        {
            // Calls a function that uses a SOAP service
            postcodes = range(postcode, model.Distance);
            foreach(Product result in query)
            {
                if (result.Author.Zipcode == null)
                    continue;
                foreach (RangeResult rr in postcodes)
                {
                    if (result.Author.Zipcode.Contains(rr.nl_fourpp.ToString()))
                        zipResults.Add(result);
                }
            }
        }

        //results = results.ToPagedList(pageNumber, PAGE_SIZE);
        return View("Resultaten", new SearchResultsVM
        {
            Products = zipResults.ToList().ToPagedList(pageNumber, PAGE_SIZE),
            Count = zipResults.Count()
        });

另外,我猜这个搜索引擎代码不是最好的,所以如果你有一些提示/改进,请与我分享。

编辑: 我的类别模型如下所示:

public class Category
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public int? ParentId { get; set; }
    public virtual Category Parent { get; set; }

    public virtual ICollection<Category> Subcategories { get; set; }

    public decimal PostCosts { get; set; }

    public byte[] Image { get; set; }

    public virtual ICollection<Product> Products { get; set; }

    public string Slug { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

编辑: 只是在类别表中添加一个额外的列,并为其提供该特定类别的“头”类别的 ID 是否明智?或者可能是一个额外的表格,将类别 ID 与其对应的头部类别结合起来?

【问题讨论】:

    标签: c# asp.net-mvc-4 search search-engine categories


    【解决方案1】:

    这是一个非常简化的版本,它返回包含其描述中的任何关键字的任何类别。希望对解决您的问题有所帮助。

    void Main()
    {
        Category c1 = new Category(){Id = 1, Description="some"};
        Category c2 = new Category() {Id = 2, Description="some description"};
        Category c3 = new Category() {Id = 3, Description="description here"};
        Category c4 = new Category() {Id = 4, Description="description"};
        Category c5 = new Category() {Id = 5, Description="some"};
    
        c1.Subcategories = new List<Category>();
        c3.Subcategories = new List<Category>();
        c1.Subcategories.Add(c2);
        c1.Subcategories.Add(c3);
        c3.Subcategories.Add(c4);
        c3.Subcategories.Add(c5);
    
        string[] keywords = new string[]{"some", "here"};
    
        FindCategories(new Category[]{c1}, keywords);
    }
    
    public IEnumerable<Category> FindCategories(IEnumerable<Category> categories,  string[] keywords)
    {   
        foreach (var category in categories)
        {
            if(keywords.Any(p => category.Description.Contains(p)))
                yield return category;
    
            if(category.Subcategories != null)
            {
                foreach (var element in FindCategories(category.Subcategories, keywords))
                {
                    yield return element;           
                }
            }
        }
    }
    

    更新 如果你想退货

    public IEnumerable<Product> FindCategories(IEnumerable<Category> categories,  string[] keywords)
    {   
        foreach (var category in categories)
        {
            if(keywords.Any(p => category.Description.Contains(p)))
            {
                foreach (var product in category.Products)
                {
                    yield return product;
                }
            }
    
            if(category.Subcategories != null)
            {
                foreach (var element in FindCategories(category.Subcategories, keywords))
                {
                    yield return element;           
                }
            }
        }
    }
    

    【讨论】:

    • 感谢您的评论!但是,如果我希望它给出IEnumerable&lt;Product&gt; 的结果,我该怎么做?
    【解决方案2】:

    考虑直接在您的数据库中进行繁重的工作。如果您使用的是 SQL Server,则可以使用 Common Table Expressions 创建递归搜索函数。

    将此搜索代码保留在数据库中意味着更容易为性能目的微调查询。

    假设您使用的是像实体框架这样的 ORM,您可以像这样调用这个新的数据库逻辑:

    var results = context.ExecuteStoreQuery<Product>("exec MySearchStoredProc").ToList();
    

    【讨论】:

      猜你喜欢
      • 2011-01-04
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多