【问题标题】:C#/Linq How to get all records by ParentId and then by FolderId recursivelyC#/Linq 如何通过 ParentId 然后通过 FolderId 递归获取所有记录
【发布时间】:2021-05-10 20:45:12
【问题描述】:

我有以下表格设置:

我需要获取绑定到某个ParentId 的所有文件夹(仅限直接子级) 我还需要能够传入FolderId,然后获取记录的完整路径以从顶层开始到达FolderId(父ID为空)

我试过.SelectMany(),但我有这个错误:

无法从用法中推断方法“Enumerable.SelectMany(IEnumerable, Func)”的类型参数。尝试明确指定类型参数

        public async Task<IList<FolderDTO>> GetFullPathByFolderId(int? parentId, bool onlyDirectChildren)
        {
            var allFolders = await GetAllFolders(false).ConfigureAwait(false);

            return allFolders.Where(x => x.ParentId == parentId)
            .Union(allFolders.Where(x => x.ParentId == parentId)
                        .SelectMany(y => GetFullPathByFolderId(y.FolderId)));

        }

所以如果传入ParentId of null,我需要返回4条记录:文件夹名称,依次为:Private、Public、Shared、Private Deleted。

如果 FolderId 被传递,我需要返回 2 条记录:文件夹名称,依次为:无标题目录、公共。

有没有办法把它组合成一个或两个方法?

CREATE TABLE [dbo].[Folders](
    [FolderId] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NULL,
    [FolderName] [varchar](150) NOT NULL,
    [FolderTypeId] [int] NOT NULL,
    [IsHidden] [bit] NOT NULL,
    [DateModified] [datetime] NOT NULL,
    [ModifiedBy] [int] NOT NULL,
    [DateSoftDeleted] [datetime] NULL,
    [SoftDeletedBy] [int] NULL,
 CONSTRAINT [PK_Folders] PRIMARY KEY CLUSTERED 
(
    [FolderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

更新代码:

这是一些代码。

我想将 FolderId 1 传递到 LINQ/C# 调用中并返回名称:PrivatePrivate1

    namespace App
    {
        /// <summary>
        /// FolderTypeDTO
        /// </summary>
        public class FolderTypeDTO
        {
            /// <summary>
            /// Gets or sets the folder type identifier.
            /// </summary>
            /// <value>
            /// The folder type identifier.
            /// </value>
            public int FolderTypeId { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the folder type.
            /// </summary>
            /// <value>
            /// The name of the folder type.
            /// </value>
            public string FolderTypeName { get; set; }
        }
    }
    
    namespace App
    {
        using System;
    
        /// <summary>
        /// Folder DTO
        /// </summary>
        public class FolderDTO
        {
            /// <summary>
            /// Gets or sets the folder identifier.
            /// </summary>
            /// <value>
            /// The folder identifier.
            /// </value>
            public int FolderId { get; set; }
    
            /// <summary>
            /// Gets or sets the parent identifier.
            /// </summary>
            /// <value>
            /// The parent identifier.
            /// </value>
            public int? ParentId { get; set; }
    
            /// <summary>
            /// Gets or sets a value indicating whether this instance has sub folders.
            /// </summary>
            /// <value>
            ///   <c>true</c> if this instance has sub folders; otherwise, <c>false</c>.
            /// </value>
            public bool HasSubFolders { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the folder parent.
            /// </summary>
            /// <value>
            /// The name of the folder parent.
            /// </value>
            public string FolderParentName { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the folder.
            /// </summary>
            /// <value>
            /// The name of the folder.
            /// </value>
            public string FolderName { get; set; }
    
            /// <summary>
            /// Gets or sets the folder type identifier.
            /// </summary>
            /// <value>
            /// The folder type identifier.
            /// </value>
            public int FolderTypeId { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the folder type.
            /// </summary>
            /// <value>
            /// The name of the folder type.
            /// </value>
            public string FolderTypeName { get; set; }
    
            /// <summary>
            /// Gets or sets a value indicating whether this instance is hidden.
            /// </summary>
            /// <value>
            ///   <c>true</c> if this instance is hidden; otherwise, <c>false</c>.
            /// </value>
            public bool IsHidden { get; set; }
    
            /// <summary>
            /// Gets or sets the level.
            /// </summary>
            /// <value>
            /// The level.
            /// </value>
            public int Level { get; set; }
    
            /// <summary>
            /// Gets or sets the date modified.
            /// </summary>
            /// <value>
            /// The date modified.
            /// </value>
            public DateTime DateModified { get; set; }
    
            /// <summary>
            /// Gets or sets the modified by.
            /// </summary>
            /// <value>
            /// The modified by.
            /// </value>
            public int ModifiedBy { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the modified by.
            /// </summary>
            /// <value>
            /// The name of the modified by.
            /// </value>
            public string ModifiedByName { get; set; }
    
            /// <summary>
            /// Gets or sets the date soft deleted.
            /// </summary>
            /// <value>
            /// The date soft deleted.
            /// </value>
            public DateTime? DateSoftDeleted { get; set; }
    
            /// <summary>
            /// Gets or sets the soft deleted by.
            /// </summary>
            /// <value>
            /// The soft deleted by.
            /// </value>
            public int? SoftDeletedBy { get; set; }
    
            /// <summary>
            /// Gets or sets the name of the soft deleted by.
            /// </summary>
            /// <value>
            /// The name of the soft deleted by.
            /// </value>
            public string SoftDeletedByName { get; set; }
        }
    }

       var folderTypeList = new List<FolderTypeDTO>
        {
            new FolderTypeDTO
            {
                FolderTypeId = 1,
                FolderTypeName = "Private"
            },
            new FolderTypeDTO
            {
                FolderTypeId = 2,
                FolderTypeName = "Public"
            },
            new FolderTypeDTO
            {
                FolderTypeId = 3,
                FolderTypeName = "Shared"
            },
        };
    
        var folderList = new List<FolderDTO>
        {
            new FolderDTO
            {
                FolderId = 1,
                ParentId = null,
                FolderName = "Private",
                FolderTypeId = 1,
                IsHidden = false,
                DateModified = DateTime.UtcNow,
                ModifiedBy = 107 // my user id in our app
            },
            new FolderDTO
            {
                FolderId = 2,
                ParentId = null,
                FolderName = "Public",
                FolderTypeId = 2,
                IsHidden = false,
                DateModified = DateTime.UtcNow,
                ModifiedBy = 107 // my user id in our app
            },
            new FolderDTO
            {
                FolderId = 3,
                ParentId = 1,
                FolderName = "Private 1",
                FolderTypeId = 1,
                IsHidden = false,
                DateModified = DateTime.UtcNow,
                ModifiedBy = 107 // my user id in our app
            }
        };

【问题讨论】:

  • 什么是GetFullPathByFolderId
  • 它应该是它自己:GetAllFoldersByFolderId(y.FolderId)
  • 可能只需要await 调用GetFullPathByFolderId()。现在你正在尝试枚举一个任务,当然这是不可枚举的。
  • @JohnWu:这不起作用:-(相同的错误消息。
  • @ttaylor27272727 - 您是否有机会以有效的 C# 代码向我们提供源数据?

标签: c# linq


【解决方案1】:

感谢您提供代码。现在很容易得到结果。

从一个查找开始,这将有助于通过parentID 生成一组递归的FolderDTO 对象。

ILookup<int?, FolderDTO> lookup = folderList.ToLookup(x => x.ParentId);

现在我们可以编写一个递归方法来返回完整的FolderDTO 对象集以及提供的parentID

IEnumerable<FolderDTO> GetHierarchically(int? parentId) =>
    from x in lookup[parentId]
    from y in GetHierarchically(x.FolderId).StartWith(x)
    select y;

现在这是一个相当简单的案例,只需执行 ConcatJoin 即可获得所需的结果。

IEnumerable<string> GetFolderNamesHierarchicallyByIdAndType(int parentId, string folderTypeName) =>
    from x in
        Enumerable
            .Concat(
                folderList.Where(f => f.FolderId == parentId),
                GetHierarchically(parentId))
    join y in folderTypeList on x.FolderTypeId equals y.FolderTypeId
    where y.FolderTypeName == folderTypeName
    select x.FolderName;

可以这样调用:

string[] names = GetFolderNamesHierarchicallyByIdAndType(1, "Private").ToArray();

我从您的样本数据中得到的结果是:

Private 
Private 1 

【讨论】:

  • @Eigmativity:非常感谢!这是一个很好的例子,会教给我更多!
猜你喜欢
  • 2021-02-25
  • 2015-10-04
  • 2012-01-26
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 2017-04-08
  • 2014-08-12
  • 1970-01-01
相关资源
最近更新 更多