You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中将三张表查询合并为单次数据库调用

如何将多次数据库调用合并为单次实现UnSaveCourseAsync方法

要把需求中的三次数据库操作合并为单次调用,核心是将校验逻辑+更新逻辑整合到一个原子性的数据库操作中,通过SQL脚本或存储过程在数据库端完成所有判断和修改,应用端仅发起一次请求即可。以下是具体实现方案:

核心思路

  1. 用事务包裹所有操作,确保原子性(任一校验不通过则回滚,避免部分执行)
  2. 先在数据库端完成用户有效性、课程存在性的校验
  3. 校验通过后,尝试更新SavedCourse表的对应记录,通过受影响行数判断是否存在该关联记录
  4. 最终返回操作结果(存在并更新成功返回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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 19:25:29