简体   繁体   English

将类别转换为人类可读的面包屑 C#

[英]Convert categories into human readable breadcrumbs C#

I need a function that converts categories into flats (see code bellow).我需要一个将类别转换为单位的 function(参见下面的代码)。 I get categories from the database and then I want to convert them into a breadcrumbs format so I can later display them in a combobox.我从数据库中获取类别,然后我想将它们转换为面包屑格式,以便以后可以在 combobox 中显示它们。

using System.Collections.Generic;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            var categories = new List<ProductCategory>
            {
                new ProductCategory { ProductCategoryId = 1, ParentId = null, Name = "Drinks" },
                new ProductCategory { ProductCategoryId = 2, ParentId = null, Name = "Food" },
                new ProductCategory { ProductCategoryId = 3, ParentId = 1, Name = "Beers" },
                new ProductCategory { ProductCategoryId = 4, ParentId = 1, Name = "Wines" },
                new ProductCategory { ProductCategoryId = 5, ParentId = 3, Name = "Local beers" },
                new ProductCategory { ProductCategoryId = 6, ParentId = 3, Name = "Foreign beers" },
                new ProductCategory { ProductCategoryId = 7, ParentId = 4, Name = "Red wines" },
                new ProductCategory { ProductCategoryId = 8, ParentId = 4, Name = "White wines" },
            };

            // todo to get below structure...

            var flats = new List<ProductCategoryFlatItem>
            {
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks",                          ProductCategoryId = 1 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Beers",                  ProductCategoryId = 3 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Beers / Local beers",    ProductCategoryId = 5 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Beers / Foreingn beers", ProductCategoryId = 6 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Wines",                  ProductCategoryId = 4 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Wines / Red wines",      ProductCategoryId = 7 },
                new ProductCategoryFlatItem { NameWithAncestors = "Drinks / Wines / White wines",    ProductCategoryId = 8 },
                new ProductCategoryFlatItem { NameWithAncestors = "Food",                            ProductCategoryId = 2 },
            };
        }
    }

    public class ProductCategory
    {
        public int ProductCategoryId { get; set; }
        public int? ParentId { get; set; }
        public string Name { get; set; }
    }

    public class ProductCategoryFlatItem
    {
        public int ProductCategoryId { get; set; }
        public string NameWithAncestors { get; set; }
    }
}

UPDATE: I successfully build a tree, and then I am trying to use tree to build breadcrumbs by searching for ancestors, see my code bellow (this is work in progress...)更新:我成功构建了一棵树,然后我尝试使用树通过搜索祖先来构建面包屑,请参阅下面的代码(这是正在进行的工作......)

 public interface IProductCategoryExtensions
    {
        List<ProductCategoryTreeItem> BuildTreeAndGetRoots(List<ProductCategory> allCategories);
        List<ProductCategoryFlatItem> CreateComboboxItems(List<ProductCategory> categories);
    }

    public class ProductCategoryExtensions : IProductCategoryExtensions
    { 
        public List<ProductCategoryTreeItem> BuildTreeAndGetRoots(List<ProductCategory> allCategories)
        {
            var treeItems = new List<ProductCategoryTreeItem>();
            var rootItems = allCategories.Where(x => x.ParentId == null);

            foreach (var rootItem in rootItems)
            {
                treeItems.Add(new ProductCategoryTreeItem
                {
                    Item = rootItem,
                    Disabled = false,
                    Parent = null,
                    Children = GetChildren(allCategories, rootItem)
                });
            }

            return treeItems;
        }

        private List<ProductCategoryTreeItem> GetChildren(List<ProductCategory> allCategories, ProductCategory productCategory)
        {
            var children = new List<ProductCategoryTreeItem>();
            var childrenTemp = allCategories.Where(x => x.ParentId == productCategory.ProductCategoryId);
            foreach (var childTemp in childrenTemp)
            {
                var child = new ProductCategoryTreeItem
                {
                    Disabled = false,
                    Item = childTemp,
                    Children = GetChildren(allCategories, childTemp),
                };

                children.Add(child);
            }

            return children;
        }

        public List<ProductCategoryFlatItem> CreateComboboxItems(List<ProductCategory> categories)
        {
            var flats = new List<ProductCategoryFlatItem>();
            var tree = BuildTreeAndGetRoots(categories);

            foreach (var treeItem in tree)
            {
                flats.Add(CreateFlatItem(treeItem, categories));

                if (treeItem.HasChildren)
                {
                    flats.AddRange(GetChildrenFlats(treeItem.Children));
                }
            }

            return flats;
        }

        private List<ProductCategoryFlatItem> GetChildrenFlats(List<ProductCategoryTreeItem> children)
        {

            var flatChildren = new List<ProductCategoryFlatItem>();

            foreach (var child in children)
            {



                //if (child.Children != null && child.Children.Count > 0)
                //    Get
            }

            return flatChildren;
        }

        private ProductCategoryFlatItem CreateFlatItem(ProductCategoryTreeItem treeItem, List<ProductCategory> allCategories)
        {
            var flat = new ProductCategoryFlatItem();

            if (treeItem.Parent == null)
            {
                flat.Description = treeItem.Item.Description;
                flat.ProductCategoryId = treeItem.Item.ProductCategoryId;
            }
            else
            {

            }


            return flat;
        }

        public List<ProductCategoryTreeItem> BuildTreeAndGetRoots(List<ProductCategory> allCategories)
        {
            var treeItems = new List<ProductCategoryTreeItem>();
            var rootItems = allCategories.Where(x => x.ParentId == null);

            foreach (var rootItem in rootItems)
            {
                treeItems.Add(new ProductCategoryTreeItem
                {
                    Item = rootItem,
                    Disabled = false,
                    Parent = null,
                    Children = GetChildren(allCategories, rootItem)
                });
            }

            return treeItems;
        }

    }

public class ProductCategoryTreeItem
    {
        public ProductCategory Item { get; set; }
        public bool Disabled { get; set; }
        public ProductCategoryTreeItem Parent { get; set; }
        public List<ProductCategoryTreeItem> Children { get; set; } = new List<ProductCategoryTreeItem>();

        public bool HasChildren
        {
            get
            {
                return Children != null && Children.Count > 0;
            }
        }
    }

Sorry this is kinda messy code, but I'll leave the refactoring to you.抱歉,这有点乱代码,但我会把重构留给你。 Assuming we have two classes:假设我们有两个类:

public class ProductCategory
{
    public int ProductCategoryId { get; set; }
    public int? ParentId { get; set; }
    public string Name { get; set; }

    public Dictionary<ProductCategory, int> AncestorsWithHierarchy { get; set; } = new Dictionary<ProductCategory, int>();
}
public class ProductCategoryFlatItem
{
    public string NameWithAncestors { get; set; }
    public int ProductCategoryId { get; set; }
}

I added AncestorsWithHierarchy to ProductCategory to be able to set up breadcrumb order right.我将AncestorsWithHierarchy添加到ProductCategory以便能够正确设置面包屑顺序。

Then you can do setup a continuous search backwards among ancestors in a recursive way, while adding the hierarchy level to use it for .OrderBy()然后,您可以以递归方式在祖先之间设置连续搜索,同时添加层次结构级别以将其用于.OrderBy()

var result = new List<ProductCategoryFlatItem>();

Func<ProductCategory, ProductCategory> FindParent = null;
FindParent = thisItem =>
{
    var parent = categories.Find(c => c.ProductCategoryId == thisItem.ParentId);
    return parent;
};

foreach (var category in categories)
{
    int hierarchyLevel = 0;

    var parent = FindParent(category);
    while (parent != null)
    {
        category.AncestorsWithHierarchy.Add(parent, hierarchyLevel);
        hierarchyLevel++;
        parent = FindParent(parent);
    }

    // Add self since we want it in the breadcrumb
    category.AncestorsWithHierarchy.Add(category, -1);

    result.Add(new ProductCategoryFlatItem()
    {
        NameWithAncestors = string.Join(" / ", category.AncestorsWithHierarchy.OrderByDescending(x => x.Value).Select(anc => anc.Key.Name)),
        ProductCategoryId = category.ProductCategoryId
    });
}

Which gives you your desired result:这会给你你想要的结果: 在此处输入图像描述

However , I would never do this kind of operation during every read.但是,我永远不会在每次阅读时都进行这种操作。 I'm assuming this data will be read much more than it'll be written.我假设这些数据的读取量将远远超过写入量。 So, what I would really do is, to move this logic where you are CRUD'ing to the database and build your breadcrumb there as a new field, and only recalculate if a category changes.所以,我真正要做的是,将这个逻辑移动到数据库中,并将你的面包屑作为一个新字段在那里构建,并且只有在类别发生变化时才重新计算。 This is much better than calculating on every single read request for every single user.这比计算每个用户的每个读取请求要好得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM