从 EF Core 开发的 SQL 构建存储过程

问题描述 投票:0回答:1

我有一个用 LINQ 编写的 EF Core 8 查询,如下所示并产生预期结果。下面,

branchIds
list
string

bool hasAccess = await _dbContext.Set<UserAssignedBranch>()
                   .Where(w => w.AgentId == agentId &&
                               branchIds.All(a => a == w.BranchId) &&
                               w.AppUserId == userId)
                   .AnyAsync();

一旦执行,我就会得到预期的输出。

我想将其转换为存储过程。因此,我打开 SQL Server Profiler 并从 EF Core 获取翻译后的 SQL 语法,如下所示:

exec sp_executesql N'SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM [UserAssignedBranch] AS [u]
        WHERE [u].[AgentId] = @__agentId_0 AND NOT EXISTS (
            SELECT 1
            FROM OPENJSON(@__branchIds_1) WITH ([value] uniqueidentifier ''$'') AS [b]
            WHERE [b].[value] <> [u].[BranchId]) AND [u].[AppUserId] = @__userId_2) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END',N'@__agentId_0 uniqueidentifier,@__branchIds_1 nvarchar(4000),@__userId_2 uniqueidentifier',@__agentId_0='FB4426D2-F237-4F7B-FA9C-08DC2CABC414',@__branchIds_1=N'["684a6a00-0a73-4c23-f525-08dc2cabc427","5a29f7fe-3fc0-42cb-a946-e3b73e09ca13"]',@__userId_2='DBEF4707-F497-43DF-9D27-08DC2CABC51B'

我尝试从此编写存储过程,这导致了以下代码:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[SP_CheckBranchAccess] 
    @UserId    NVARCHAR(100),
    @AgentId   NVARCHAR(100),
    @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

这就是我从 C# 调用存储过程的方式:

var strbranchIds = branchIds.Select(s => s.ToString()).ToList();

List<SqlParameter> parms = new()
    {
        new SqlParameter { ParameterName = "@AgentId", Value = agentId.ToString() },
        new SqlParameter { ParameterName = "@UserId", Value = userId.ToString() },
        new SqlParameter { ParameterName = "@BranchIds", Value = string.Join(',',strbranchIds ?? new List<string>()) }
    };

var hasClaim = await _dbContext.Set<SP_CheckBranchAccess>()
                               .FromSqlRaw("EXEC SP_CheckBranchAccess @AgentId, @UserId, @BranchIds", parms.ToArray())
                               .ToListAsync(cancellationToken: token);

但在这种情况下,我没有得到 LINQ-to-SQL 的预期结果。有人能帮我解决这个问题吗?

sql-server stored-procedures entity-framework-core
1个回答
0
投票

请勿使用

.Set<T>.FromSqlRaw
,因为这旨在从 SQL 返回并填充实体定义。在您的情况下,您实际上只需要 True/False 的标量值。相反,请尝试使用所需参数(包括结果的 OUTPUT 参数)
_dbContext.Database.ExecuteSqlCommand

© www.soinside.com 2019 - 2024. All rights reserved.