ASP.NET Core Web API中,用户与计划一对多关系下如何设置当前计划?
问题描述
我正在开发ASP.NET Core Web API项目,User与Plan已实现正常的一对多关系。现在希望在多端(Plan)中设置“当前计划”,即除User实体中存储的所有计划列表外,还要指定单个计划为当前计划。
我的Plan类:
public class Plan { public Plan() { } public Plan(string name, string description, User user) { this.Name = name; this.Description = description; this.Workouts = new HashSet<Workout>(); this.User = user; this.UserId = user.Id; this.status = PlanStatus.UnStarted; } [Key] public int PlanId { get; set; } public string Name { get; set; } public string Description { get; set; } public string UserId { get; set; } [ForeignKey("UserId")] public virtual User User { get; set; } public PlanStatus status; public virtual ICollection<Workout> Workouts { get; set; } }
PlanStatus枚举:
public enum PlanStatus { Unstarted, InProgress, Completed }
我的User类:
public class User : IdentityUser { public User() { } public User(string name, string email) { this.UserName = name; this.Email = email; this.Plans = new HashSet<Plan>(); this.Exercises = new HashSet<Exercise>(); } public virtual ICollection<Plan> Plans { get; set; } public virtual ICollection<Exercise> Exercises { get; set; } }
我想到两种方案:一是在User类中添加currentPlanId,但需要维护;二是通过检查用户所有Plan的PlanStatus,将处于InProgress状态的计划作为当前计划(同一时间仅一个计划处于该状态)。请问哪种方案更好,或是有其他实现方式?
方案分析与建议
方案一:User类添加CurrentPlanId
优点
- 查询效率高:直接通过User的关联字段获取当前计划,无需遍历或过滤所有Plan,用户计划数量较多时性能优势明显。
- 逻辑直观:当前计划的关联关系明确,业务代码无需额外处理状态判断逻辑。
缺点
- 一致性维护成本高:切换当前计划、完成计划时,需同步更新
CurrentPlanId和旧计划状态(若需要),业务代码复杂度提升,易出现数据不一致问题。
方案二:通过PlanStatus.InProgress标记当前计划
优点
- 语义贴合:
InProgress本身代表计划正在执行,与“当前计划”的业务语义完全匹配,无需额外冗余字段。 - 天然唯一性:可通过数据库约束或业务逻辑保证同一用户仅存在一个
InProgress状态的Plan,避免数据冲突。
缺点
- 查询成本略高:每次获取当前计划需过滤用户所有Plan,需为
Plan表的UserId和status字段添加联合索引优化性能,否则计划数量大时会影响效率。 - 状态切换需严谨:启动新计划时,必须先将旧的
InProgress计划改为Completed或Unstarted,否则会出现多个当前计划的情况。
推荐选择
如果“当前计划”的核心语义就是“正在执行的计划”,优先选方案二,它让状态与业务逻辑深度绑定,减少冗余。但需注意两点:
- 数据库层面添加联合唯一约束:对
Plan表的UserId和status字段设置约束,确保同一用户最多一个InProgress计划。 - 封装状态切换逻辑:编写统一的方法(如
SetAsCurrentPlan),自动处理旧计划状态变更和新计划状态设置,避免手动操作出错。
若业务中“当前计划”不一定等于“正在执行的计划”(比如用户可标记已完成计划为当前参考),则选方案一,此时需在业务代码中严格维护CurrentPlanId的一致性,比如更新计划状态、删除计划时同步更新该字段。
其他实现方式
- 单独创建
UserCurrentPlan关联表:适用于未来可能扩展多当前计划的场景,但当前需求下过于复杂,增加数据库结构冗余,不推荐。
内容的提问来源于stack exchange,提问作者Judith Black
相关产品推荐
相关产品推荐

