如何简化根据用户ID获取UserInfoDto的LINQ查询?
简化LINQ查询实现用户信息获取的方案
前提模型
public record Project( int Id, int AuthorId, int TeamId, string Name, string Description, DateTime CreatedAt, DateTime Deadline) public record Task( int Id, int ProjectId, int PerformerId, string Name, string Description, TaskState State, DateTime CreatedAt, DateTime? FinishedAt) public record User( int Id, int? TeamId, string FirstName, string LastName, string Email, DateTime RegisteredAt, DateTime BirthDay)
需求目标
根据用户ID获取UserInfoDto,包含:
UserDto User:用户基础信息ProjectDto LastProject:用户最后创建的项目(按创建时间排序),无项目时为nullint LastProjectTasksCount:最后一个项目的任务总数,无项目/无任务时为0int NotFinishedOrCanceledTasksCount:用户作为执行者的未完成/已取消任务总数(状态为ToDo/InProgress/Canceled),无任务时为0TaskDto LongestTask:用户作为执行者的耗时最长任务(按结束时间-创建时间计算,需考虑未完成任务)
原实现的问题
原代码通过多次多表Join关联用户、任务、项目,导致数据冗余膨胀,后续必须用Distinct去重,既影响性能,又让逻辑耦合在一起,可读性差;同时未妥善处理用户无项目时的空引用问题。
简化后的实现
public async Task<UserInfoDto> GetUserInfoAsync(int userId) { var tasks = await _dataProvider.GetTasksAsync(); var users = await _dataProvider.GetUsersAsync(); var projects = await _dataProvider.GetProjectsAsync(); // 定位目标用户 var targetUser = users.FirstOrDefault(u => u.Id == userId); if (targetUser == null) return null; // 处理用户创建的项目相关逻辑 var userProjects = projects.Where(p => p.AuthorId == userId).ToList(); var lastProject = userProjects.MaxBy(p => p.CreatedAt); var lastProjectTasksCount = lastProject == null ? 0 : tasks.Count(t => t.ProjectId == lastProject.Id); // 处理用户作为执行者的任务相关逻辑 var userTasks = tasks.Where(t => t.PerformerId == userId).ToList(); var notFinishedOrCanceledCount = userTasks.Count(t => t.State is TaskState.ToDo or TaskState.InProgress or TaskState.Canceled); // 计算最长耗时任务:未完成任务用当前时间与创建时间的差值计算时长(可根据需求调整规则) var longestTask = userTasks .Select(t => new { Task = t, Duration = t.FinishedAt.HasValue ? t.FinishedAt.Value - t.CreatedAt : DateTime.Now - t.CreatedAt }) .MaxBy(x => x.Duration)? .Task; // 映射返回DTO return _mapper.Map<UserInfoDto>(new { User = targetUser, LastProject = lastProject, LastProjectTasksCount = lastProjectTasksCount, NotFinishedOrCanceledTasksCount = notFinishedOrCanceledCount, LongestTask = longestTask }); }
简化关键点
- 拆分逻辑模块:将用户查询、项目处理、任务处理拆分为独立部分,避免多表Join导致的逻辑混乱
- 精准过滤数据:直接针对目标用户筛选其项目和任务,避免全局Join后再过滤,提升性能
- 避免冗余去重:基于目标用户的专属数据集操作,无需额外
Distinct处理 - 明确边界处理:主动处理用户无项目、无任务的场景,避免空引用异常
- 提升可读性:每个代码块只负责单一逻辑,调试和维护更便捷
内容的提问来源于stack exchange,提问作者Illusion
相关产品推荐
相关产品推荐

