如何在C#中将三张表查询合并为单次数据库调用
如何将多次数据库调用合并为单次实现UnSaveCourseAsync方法
要把需求中的三次数据库操作合并为单次调用,核心是将校验逻辑+更新逻辑整合到一个原子性的数据库操作中,通过SQL脚本或存储过程在数据库端完成所有判断和修改,应用端仅发起一次请求即可。以下是具体实现方案:
核心思路
- 用事务包裹所有操作,确保原子性(任一校验不通过则回滚,避免部分执行)
- 先在数据库端完成用户有效性、课程存在性的校验
- 校验通过后,尝试更新
SavedCourse表的对应记录,通过受影响行数判断是否存在该关联记录 - 最终返回操作结果(存在并更新成功返回true,否则返回false)
方案一:EF Core执行原生SQL脚本
直接在C#方法中编写包含完整逻辑的SQL脚本,通过EF Core执行单次数据库调用:
public async Task<bool> UnSaveCourseAsync(int userId, int courseId) { var sqlScript = @" BEGIN TRANSACTION; -- 校验用户是否有效、课程是否存在 DECLARE @IsUserValid BIT = (SELECT CASE WHEN EXISTS(SELECT 1 FROM [User] WHERE Id = @UserId AND IsValid = 1) THEN 1 ELSE 0 END); DECLARE @IsCourseExists BIT = (SELECT CASE WHEN EXISTS(SELECT 1 FROM Playlist WHERE Id = @CourseId) THEN 1 ELSE 0 END); -- 任一校验不通过则回滚,返回false IF @IsUserValid = 0 OR @IsCourseExists = 0 BEGIN ROLLBACK TRANSACTION; SELECT 0 AS OperationResult; RETURN; END; -- 更新已保存课程,标记为删除并取消激活 DECLARE @UpdatedRowCount INT; UPDATE SavedCourse SET IsDeleted = 1, IsActive = 0 WHERE UserId = @UserId AND CourseId = @CourseId AND IsDeleted = 0; SET @UpdatedRowCount = @@ROWCOUNT; COMMIT TRANSACTION; -- 根据更新行数返回结果:有行更新则返回true,否则false SELECT CASE WHEN @UpdatedRowCount > 0 THEN 1 ELSE 0 END AS OperationResult; "; var parameters = new[] { new SqlParameter("@UserId", userId), new SqlParameter("@CourseId", courseId) }; // 执行SQL并获取结果 var result = await _dbContext.Database.SqlQueryRaw<int>(sqlScript, parameters).SingleOrDefaultAsync(); return result == 1; }
方案二:使用数据库存储过程
将逻辑封装为存储过程,应用端调用存储过程完成操作(适合逻辑复杂或需要复用的场景)
1. 创建存储过程
CREATE PROCEDURE dbo.UnSaveCourse @UserId INT, @CourseId INT, @OperationResult BIT OUTPUT AS BEGIN SET NOCOUNT ON; BEGIN TRANSACTION; -- 校验用户和课程 DECLARE @IsUserValid BIT = (SELECT CASE WHEN EXISTS(SELECT 1 FROM [User] WHERE Id = @UserId AND IsValid = 1) THEN 1 ELSE 0 END); DECLARE @IsCourseExists BIT = (SELECT CASE WHEN EXISTS(SELECT 1 FROM Playlist WHERE Id = @CourseId) THEN 1 ELSE 0 END); IF @IsUserValid = 0 OR @IsCourseExists = 0 BEGIN ROLLBACK TRANSACTION; SET @OperationResult = 0; RETURN; END; -- 更新SavedCourse记录 DECLARE @UpdatedRowCount INT; UPDATE SavedCourse SET IsDeleted = 1, IsActive = 0 WHERE UserId = @UserId AND CourseId = @CourseId AND IsDeleted = 0; SET @UpdatedRowCount = @@ROWCOUNT; COMMIT TRANSACTION; SET @OperationResult = CASE WHEN @UpdatedRowCount > 0 THEN 1 ELSE 0 END; END
2. C#中调用存储过程
public async Task<bool> UnSaveCourseAsync(int userId, int courseId) { // 定义参数,包含输出参数 var userIdParam = new SqlParameter("@UserId", userId); var courseIdParam = new SqlParameter("@CourseId", courseId); var resultParam = new SqlParameter("@OperationResult", SqlDbType.Bit) { Direction = ParameterDirection.Output }; // 执行存储过程 await _dbContext.Database.ExecuteSqlRawAsync( "EXEC dbo.UnSaveCourse @UserId, @CourseId, @OperationResult OUTPUT", userIdParam, courseIdParam, resultParam); // 解析输出参数返回结果 return (bool)resultParam.Value; }
关键注意事项
- 替换表/字段名:确保
[User]、Playlist、SavedCourse的字段名与你的数据库实际结构匹配(比如用户有效性字段如果不是IsValid,需调整校验逻辑) - 原子性保障:事务确保了校验和更新操作要么全部成功,要么全部回滚,避免数据不一致
- 性能优化:所有逻辑在数据库端完成,减少了应用与数据库的网络交互次数
内容的提问来源于stack exchange,提问作者Surbhi
相关产品推荐
相关产品推荐

