# 组织单位查询 **本文档中引用的文件** - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs) - [OrganizationUnitController.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.HttpApi/LINGYUN/Abp/Identity/OrganizationUnitController.cs) - [EfCoreOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs) - [IOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IOrganizationUnitRepository.cs) - [OrganizationUnitDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitDto.cs) - [OrganizationUnitGetByPagedDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs) - [OrganizationUnitGetListSpecification.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitGetListSpecification.cs) ## 目录 1. [简介](#简介) 2. [核心查询方法](#核心查询方法) 3. [分页与过滤机制](#分页与过滤机制) 4. [树形结构展平策略](#树形结构展平策略) 5. [组织单位仓储优化技术](#组织单位仓储优化技术) 6. [层级信息与统计获取](#层级信息与统计获取) 7. [API调用示例](#api调用示例) 8. [性能优化建议](#性能优化建议) ## 简介 本文档详细描述了abp-next-admin系统中组织单位查询功能的实现。系统提供了丰富的查询接口,支持分页、过滤、排序和树形结构展平等功能。通过这些接口,开发者可以高效地查询组织单位信息,包括完整的树形结构、特定层级的子节点以及包含用户统计和权限继承数据的详细信息。 **Section sources** - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs) - [OrganizationUnitController.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.HttpApi/LINGYUN/Abp/Identity/OrganizationUnitController.cs) ## 核心查询方法 系统提供了多个核心查询方法来满足不同的查询需求: - `GetListAsync`: 分页查询组织单位列表,支持过滤和排序 - `GetAllListAsync`: 获取所有组织单位列表 - `GetAsync`: 根据ID获取单个组织单位 - `GetRootAsync`: 获取根节点组织单位 - `FindChildrenAsync`: 查找指定组织单位的子节点 - `GetLastChildOrNullAsync`: 获取最后一个子节点或空值 ```mermaid sequenceDiagram participant Client as "客户端" participant Controller as "OrganizationUnitController" participant AppService as "OrganizationUnitAppService" participant Repository as "EfCoreOrganizationUnitRepository" Client->>Controller : GetListAsync(input) Controller->>AppService : GetListAsync(input) AppService->>AppService : 创建OrganizationUnitGetListSpecification AppService->>Repository : GetCountAsync(specification) AppService->>Repository : GetListAsync(specification, sorting, maxResultCount, skipCount) Repository-->>AppService : 返回计数和列表 AppService-->>Controller : 返回PagedResultDto Controller-->>Client : 返回分页结果 ``` **Diagram sources** - [OrganizationUnitController.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.HttpApi/LINGYUN/Abp/Identity/OrganizationUnitController.cs#L79-L82) - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs#L96-L123) - [EfCoreOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs#L35-L50) **Section sources** - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs#L67-L205) - [OrganizationUnitController.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.HttpApi/LINGYUN/Abp/Identity/OrganizationUnitController.cs#L38-L149) ## 分页与过滤机制 系统实现了标准的分页和过滤机制,通过`OrganizationUnitGetByPagedDto`输入参数和`OrganizationUnitGetListSpecification`规范类来实现。 ### 分页参数 分页查询使用`PagedAndSortedResultRequestDto`基类,包含以下参数: - `MaxResultCount`: 每页最大结果数(默认10) - `SkipCount`: 跳过的记录数(用于分页) - `Sorting`: 排序规则 ### 过滤实现 过滤功能通过`OrganizationUnitGetListSpecification`类实现,该类继承自ABP框架的`Specification`模式: ```csharp public override Expression> ToExpression() { Expression> expression = _ => true; return expression.AndIf(!Input.Filter.IsNullOrWhiteSpace(), x => x.DisplayName.Contains(Input.Filter) || x.Code.Contains(Input.Filter)); } ``` 此实现允许在显示名称(DisplayName)和编码(Code)字段上进行模糊搜索。 ```mermaid flowchart TD Start([开始]) --> CreateSpec["创建OrganizationUnitGetListSpecification"] CreateSpec --> GetCount["调用GetCountAsync获取总数"] GetCount --> GetList["调用GetListAsync获取分页数据"] GetList --> MapDto["映射到OrganizationUnitDto"] MapDto --> Return["返回PagedResultDto"] Return --> End([结束]) ``` **Diagram sources** - [OrganizationUnitGetByPagedDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs) - [OrganizationUnitGetListSpecification.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitGetListSpecification.cs) - [EfCoreOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs) **Section sources** - [OrganizationUnitGetListSpecification.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitGetListSpecification.cs#L6-L23) - [OrganizationUnitGetByPagedDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitGetByPagedDto.cs#L4-L7) ## 树形结构展平策略 系统采用路径枚举模式(Path Enumeration Pattern)来优化树形结构的查询性能。每个组织单位都有一个Code属性,该属性包含了从根节点到当前节点的完整路径。 ### 展平策略实现 当需要查询某个组织单位及其所有子节点时,系统使用Code字段的前缀匹配: ```csharp // 查询某个组织单位下的所有用户(包括子节点) var query = from userOu in dbContext.Set() join user in (await GetDbSetAsync()) on userOu.UserId equals user.Id join ou in dbContext.Set() on userOu.OrganizationUnitId equals ou.Id where ou.Code.StartsWith(code) select user; ``` 这种策略避免了递归查询,大大提高了查询效率。 ### 递归查询支持 对于需要精确控制递归深度的场景,系统提供了`FindChildrenAsync`方法,通过`OrganizationUnitGetChildrenDto`参数中的`Recursive`标志来控制是否递归查询所有子节点。 ```mermaid classDiagram class OrganizationUnit { +Guid Id +Guid? ParentId +string Code +string DisplayName +DateTime CreationTime } class OrganizationUnitDto { +Guid Id +Guid? ParentId +string Code +string DisplayName +DateTime CreationTime +DateTime CreatorId +DateTime LastModificationTime +DateTime LastModifierId } class OrganizationUnitGetChildrenDto { +Guid Id +bool Recursive } OrganizationUnit <|-- OrganizationUnitDto : 映射 OrganizationUnitAppService --> OrganizationUnitManager : 使用 OrganizationUnitAppService --> IOrganizationUnitRepository : 使用 OrganizationUnitAppService --> OrganizationUnitGetChildrenDto : 输入 ``` **Diagram sources** - [OrganizationUnitDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitDto.cs) - [OrganizationUnitGetChildrenDto.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application.Contracts/LINGYUN/Abp/Identity/Dto/OrganizationUnitGetChildrenDto.cs) - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs) **Section sources** - [EfCoreIdentityUserRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs#L215-L237) - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs#L75-L82) ## 组织单位仓储优化技术 组织单位仓储层实现了多种优化技术来提高查询性能。 ### 自定义仓储接口 系统扩展了ABP框架的默认仓储,添加了专门用于分页查询的方法: ```csharp public interface IOrganizationUnitRepository : Volo.Abp.Identity.IOrganizationUnitRepository { Task GetCountAsync( ISpecification specification, CancellationToken cancellationToken = default); Task> GetListAsync( ISpecification specification, string sorting = nameof(OrganizationUnit.Code), int maxResultCount = 10, int skipCount = 0, bool includeDetails = false, CancellationToken cancellationToken = default); } ``` ### 实现细节 `EfCoreOrganizationUnitRepository`实现了上述接口,提供了高效的查询方法: ```csharp public async virtual Task> GetListAsync( ISpecification specification, string sorting = nameof(OrganizationUnit.Code), int maxResultCount = 10, int skipCount = 0, bool includeDetails = false, CancellationToken cancellationToken = default) { if (sorting.IsNullOrWhiteSpace()) { sorting = nameof(OrganizationUnit.Code); } return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(specification.ToExpression()) .OrderBy(sorting) .PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); } ``` **Section sources** - [IOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IOrganizationUnitRepository.cs#L0-L21) - [EfCoreOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs#L0-L38) ## 层级信息与统计获取 系统提供了多种方法来获取组织单位的层级信息和相关统计。 ### 层级信息 - `ParentId`: 指向父级组织单位的GUID - `Code`: 包含完整路径的编码,如"001.002.003" - `DisplayName`: 显示名称 ### 用户统计 可以通过以下方法获取组织单位的用户统计信息: - `GetUsersInOrganizationUnitCountAsync`: 获取指定组织单位的用户数量 - `GetUsersInOrganizationUnitWithChildrenCountAsync`: 获取指定组织单位及其所有子节点的用户总数 ### 权限继承 系统通过角色与组织单位的关联实现权限继承: - `GetRolesInOrganizationUnitAsync`: 获取直接分配给该组织单位的角色 - `GetRolesInOrganizationUnitWithChildrenAsync`: 获取该组织单位及其子节点的所有角色 ```mermaid erDiagram ORGANIZATION_UNIT ||--o{ USER_ORGANIZATION_UNIT : "包含" ORGANIZATION_UNIT ||--o{ ORGANIZATION_UNIT_ROLE : "包含" IDENTITY_USER ||--o{ USER_ORGANIZATION_UNIT : "属于" IDENTITY_ROLE ||--o{ ORGANIZATION_UNIT_ROLE : "属于" ORGANIZATION_UNIT { guid Id PK guid ParentId FK string Code string DisplayName datetime CreationTime } USER_ORGANIZATION_UNIT { guid UserId PK,FK guid OrganizationUnitId PK,FK } ORGANIZATION_UNIT_ROLE { guid RoleId PK,FK guid OrganizationUnitId PK,FK } IDENTITY_USER { guid Id PK string UserName string Name string Email } IDENTITY_ROLE { guid Id PK string Name string DisplayName } ``` **Diagram sources** - [EfCoreIdentityUserRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs#L132-L152) - [EfCoreIdentityRoleRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs#L83-L95) **Section sources** - [IIdentityUserRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserRepository.cs#L71-L128) - [EfCoreIdentityUserRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs#L97-L130) ## API调用示例 以下是各种查询场景的API调用示例: ### 按名称搜索 ```http GET /api/identity/organization-units?Filter=开发 HTTP/1.1 ``` 此请求将返回显示名称或编码中包含"开发"的所有组织单位。 ### 分页查询 ```http GET /api/identity/organization-units?MaxResultCount=20&SkipCount=0&Sorting=DisplayName HTTP/1.1 ``` 此请求将返回按显示名称排序的前20个组织单位。 ### 获取完整树形结构 ```http GET /api/identity/organization-units/all HTTP/1.1 ``` 此请求将返回所有组织单位的扁平化列表,前端可据此重建树形结构。 ### 按层级查询子节点 ```http POST /api/identity/organization-units/find-children HTTP/1.1 Content-Type: application/json { "id": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", "recursive": true } ``` 此请求将返回指定组织单位的所有子节点(包括递归子节点)。 ### 获取根节点 ```http GET /api/identity/organization-units/root-node HTTP/1.1 ``` 此请求将返回所有顶级组织单位(无父级的组织单位)。 **Section sources** - [OrganizationUnitController.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.HttpApi/LINGYUN/Abp/Identity/OrganizationUnitController.cs#L38-L149) ## 性能优化建议 为了确保组织单位查询的高性能,建议采取以下措施: ### 索引建议 在数据库中为以下字段创建索引: - `OrganizationUnit.Code` (前缀索引,支持StartsWith查询) - `OrganizationUnit.ParentId` (外键索引) - `OrganizationUnit.DisplayName` (全文索引或普通索引) - `OrganizationUnit.Code` 和 `OrganizationUnit.DisplayName` 的组合索引 ### 缓存策略 1. **全量缓存**: 对于不经常变化的组织单位树,可以缓存完整的组织单位列表。 2. **分层缓存**: 按层级缓存组织单位,减少重复查询。 3. **热点数据缓存**: 缓存频繁访问的组织单位及其子节点。 ### 查询优化 - 使用`GetAllListAsync`获取完整列表后在内存中构建树形结构,而不是多次递归查询。 - 对于大型组织结构,优先使用基于Code前缀的查询而非递归CTE查询。 - 合理设置分页大小,避免一次性加载过多数据。 **Section sources** - [EfCoreOrganizationUnitRepository.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs) - [OrganizationUnitAppService.cs](file://aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/OrganizationUnitAppService.cs)