簡體   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