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

EF Core 8 LINQ转存储过程结果不符,请求修正

问题分析与修正方案

你的问题出在两个关键环节:存储过程逻辑与原LINQ不一致,以及C#调用时分支ID参数格式错误,以下是具体修正步骤:

1. 修正存储过程的逻辑错误

原LINQ中的branchIds.All(a => a == w.BranchId),EF Core生成的SQL逻辑是NOT EXISTS (SELECT 1 FROM OPENJSON(...) WHERE [b].[value] <> [u].[BranchId])——意思是「分支列表中不存在与当前记录BranchId不相等的项」,即所有分支ID都匹配当前记录的BranchId。

但你编写的存储过程错误地将条件写成WHERE [b].[value] = [u].[BranchId]后加NOT EXISTS,完全反转了原逻辑。同时,参数类型应与数据库字段一致(用UNIQUEIDENTIFIER而非NVARCHAR(100)),避免类型转换问题。

修正后的存储过程:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[SP_CheckBranchAccess] 
    @UserId    UNIQUEIDENTIFIER,
    @AgentId   UNIQUEIDENTIFIER,
    @BranchIds NVARCHAR(MAX) = N'[]'
AS
BEGIN
    DECLARE @Result BIT;

    SELECT @Result = CASE
        WHEN EXISTS (
            SELECT 1
            FROM [UserAssignedBranch] AS [u]
            WHERE [u].[AgentId] = @AgentId 
              AND NOT EXISTS (
                  SELECT 1
                  FROM OPENJSON(@BranchIds) WITH ([value] UNIQUEIDENTIFIER '$') AS [b]
                  WHERE [b].[value] <> [u].[BranchId] -- 修正此处的不等号逻辑
              ) 
              AND [u].[AppUserId] = @UserId
        ) THEN CAST(1 AS BIT)
        ELSE CAST(0 AS BIT)
    END;

    SELECT @Result AS [Result];
END

2. 修正C#调用的参数格式与顺序错误

EF Core生成的SQL中,分支ID参数是JSON数组格式(如["xxx","xxx"]),但你当前用string.Join(',', strbranchIds)生成的是逗号分隔字符串,会导致OPENJSON无法正确解析。此外,存储过程参数顺序与调用时的顺序不匹配,会导致参数传递错位。

修正后的C#调用代码:

// 将分支ID序列化为JSON数组格式
var branchIdsJson = System.Text.Json.JsonSerializer.Serialize(branchIds ?? new List<string>());

List<SqlParameter> parms = new()
{
    new SqlParameter { ParameterName = "@UserId", Value = userId }, // 按存储过程参数顺序传递
    new SqlParameter { ParameterName = "@AgentId", Value = agentId },
    new SqlParameter { ParameterName = "@BranchIds", Value = branchIdsJson }
};

// 调用存储过程并获取结果
var result = await _dbContext.Set<bool>()
                             .FromSqlRaw("EXEC SP_CheckBranchAccess @UserId, @AgentId, @BranchIds", parms.ToArray())
                             .FirstOrDefaultAsync(cancellationToken: token);

// 若使用SP_CheckBranchAccess实体类,可改为:
// var accessResult = await _dbContext.Set<SP_CheckBranchAccess>()
//                                   .FromSqlRaw("EXEC SP_CheckBranchAccess @UserId, @AgentId, @BranchIds", parms.ToArray())
//                                   .FirstOrDefaultAsync(token);
// bool hasClaim = accessResult?.Result ?? false;

额外注意点

  • 直接传递Guid类型参数而非字符串,减少类型转换的潜在问题;
  • 调用存储过程时,参数顺序必须与存储过程定义的顺序一致,或明确指定参数名(如EXEC SP_CheckBranchAccess @UserId = @UserId, @AgentId = @AgentId, @BranchIds = @BranchIds),避免参数错位。

内容的提问来源于stack exchange,提问作者thanzeel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:53:15