繁体   English   中英

C# 递归查询加载数据耗时过多

[英]Recursive query takes too much time to load data in C#

*我写了一个递归查询来获得无限的菜单层。 查询可以很好地提供准确的结果,但加载时间太长。 大概需要 10 到 15 秒。 如果我需要做任何事情来提高性能,请帮助我。 我已经提供了所有代码来找出问题所在。 为了从实体映射到视图 model 我使用了自动映射器。 *

实体:

public class Menus
    {
        public int Id { get; set; }
        public string Icon { get; set; }
        public string Label { get; set; }
        public string To { get; set; }
        [ForeignKey("Parents")]
        public int? ParentsId { get; set; }
        public string Key { get; set; }
        public bool? Permitted { get; set; }
        public Menus Parents { get; set; }
        public ICollection<Menus> Subs { get; set; }
        public ICollection<MenusRole> MenusRoles { get; set; }
    }

询问:

public async Task<IEnumerable<Menus>> GetAllMenusAsync()
        {
            List<Menus> temp = await ApplicationDbContext
                .Menus
                .Include(x => x.Subs)
                .Where(x => x.Parents == null)
                .Select(f => new Menus
                {
                    Id = f.Id,
                    Key = f.Key,
                    Label = f.Label,
                    To = f.To,
                    Icon = f.Icon,
                    ParentsId = f.ParentsId,
                    Subs = f.Subs
                }).ToListAsync();
            return Get_all_menus(temp);
        }


public List<Menus> Get_all_menus(List<Menus> menus)
        {
            int z = 0;
            List<Menus> menuList = new List<Menus>();
            if (menus.Count > 0)
            {
                menuList.AddRange(menus);
            }
            foreach (Menus item in menus)
            {
                Menus menu = ApplicationDbContext
                    .Menus
                    .Include(y => y.Subs)
                    .Where(y => y.Id == item.Id)
                    .Select(y => new Menus
                    {
                        Id = y.Id,
                        Key = y.Key,
                        Label = y.Label,
                        To = y.To,
                        Icon = y.Icon,
                        ParentsId = y.ParentsId,
                        Subs = y.Subs,
                        Permitted = true
                    }).First();

                if (menu.Subs == null)
                {
                    z++;
                    continue;
                }

                List<Menus> subMenu = menu.Subs.ToList();
                menu.Subs = Get_all_menus(subMenu);
                menuList[z] = menu;
                z++;
            }
            return menuList;
        }

在 Controller

 [HttpGet("get-all-menus")]
        public async Task<ActionResult> GetAllMenus()
        {
            var menus = await _menusService.GetAllMenus();
            var menusResources = _mapper.Map<IEnumerable<Menus>, IEnumerable<MenusResourceForSidebar>>(menus);
            return Ok(menusResources);
        }

查看Model

public string Id { get; set; }
        public string Icon { get; set; }
        public string Label { get; set; }
        public string To { get; set; }
        public bool? Permitted { get; set; }
        public ICollection<MenusResourceForSidebar> Subs { get; set; }

与其加载根菜单,然后在单独的查询中加载子项,不如在一个查询中加载整个集合,然后填充导航链接。

public async Task<IEnumerable<Menus>> GetAllMenusAsync()
{
    List<Menus> temp = await ApplicationDbContext.Menus.ToList();
    List<Menus> topLevel = new List<Menu>();

    foreach (var menu in temp)
    {
        if (menu.ParentsId == null)
        {
            topLevel.Add(menu);
            continue;
        }

        var parent = temp.Find(x => x.Id == temp.ParentsId.Value);
        if (parent.Subs == null)
            parent.Subs = new List<Menus>();

        parent.Subs.Add(menu);
    }

    return topLevel;
}

你应该能够做到:

context.Menus.Include(m => m.Subs).ToList();

EFCore 中的关系修复将为您将所有菜单链接在一起。 在以后的 EF 中,您甚至不需要 Include..

context.Menus.ToList();

这是 SSMS 中的一个表:

在此处输入图像描述

这是数据:

在此处输入图像描述

在这里,它在绘图程序中被切碎并重新排列成一棵树:

在此处输入图像描述

这是脚手架实体:

// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System.Collections.Generic;

namespace ConsoleApp7net5.Models
{
    public partial class Menu
    {
        public Menu()
        {
            InverseParent = new HashSet<Menu>();
        }

        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Label { get; set; }

        public virtual Menu Parent { get; set; }
        public virtual ICollection<Menu> InverseParent { get; set; }
    }
}

这是我们在要求 EFC(在我的例子中是 5)仅使用 ToList 下载所有内容后看到的内容:

在此处输入图像描述

当然,从根开始可能是有意义的(或多个根,但我的数据只有一个)

在此处输入图像描述


不要给类复数名称(菜单),顺便说一句,如果它们不是集合/可枚举(父母),也不要给属性复数名称 - 这会导致代码非常混乱

暂无
暂无

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

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