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

.NET 9 Blazor项目中动态拼接带SqlParameter的存储过程EXEC语句时遇类型转换错误的求助

.NET 9 Blazor项目中动态拼接带SqlParameter的存储过程EXEC语句时遇类型转换错误的求助

各位好,我现在在开发一个基于.NET 9的Blazor Web应用,遇到了一个关于动态拼接带SqlParameter的存储过程执行语句的问题,想请大家帮忙看看。

我的需求是:写一个方法,能动态处理SqlParameter[]参数,把它们和EXEC {storedProcedure}拼接成FormattableString,不用手动逐个指定参数的索引(比如不能每次都写{sqlParameterparam[0]}, {sqlParameterparam[1]}这种固定索引的写法)。

我一开始写的方法是这样的:

public static FormattableString FromSqlSQLParamDynamic(string storedProcedure, string[] paramName, params object?[] parameters)
{
    if (paramName.Length != parameters.Length)
    {
        throw new ArgumentException("Parameters count mismatch.");
    }

    SqlParameter[] sqlParameterparam = [.. paramName.Select((name, i) => new SqlParameter(name, parameters[i] ?? DBNull.Value) )];

    FormattableString sqlQuery = $"EXEC {storedProcedure} {string.Join(", ", sqlParameterparam.Select(p => p))}";
    // 预期生成:EXEC myStoredProcedure id, random_text, key
    return sqlQuery;
}

我确认sqlParameterparam的初始化是正确的,但动态拼接的时候却报错了,错误信息是:

An unhandled exception occurred while processing the request.
SqlException: Error converting data type nvarchar to int.
Microsoft.Data.SqlClient.SqlCommand+<>c.b__211_0(Task result)

我理解这个错误是因为参数的数据类型没有正确对应,但如果我把拼接语句改成手动指定每个参数的索引,就完全正常:

FormattableString sqlQuery = $"EXEC {storedProcedure} {sqlParameterparam[0]}, {sqlParameterparam[1]}, {sqlParameterparam[2]}";

但这种写法不够动态,参数数量变了就得改代码,不是我想要的效果。

下面是我的相关代码上下文:

SQLServerHelper类的GetRandTextsFromSqlROAsync方法

using Microsoft.EntityFrameworkCore;
using MyProject.Models.SQLServer;
using MyProject.Data.SQLServer;

class SQLServerHelper(SQLServerContext context)
{
    private readonly SQLServerContext _context = context;

    public async Task<List<RandText>> GetRandTextsFromSqlROAsync(string storedProcedure, params object?[] parameters)
    {
        string[] paramNames = ["id", "random_text", "key"];
        if (parameters.Length != paramNames.Length)
        {
            throw new ArgumentException("Parameters count mismatch.");
        }

        var sqlParam = SQLDbSettings.FromSqlSQLParamDynamic(storedProcedure, paramNames, parameters);

        return await _context.RandText
            .FromSql(sqlParam)
            .AsNoTracking()
            .ToListAsync();
    }
}

Blazor页面中的调用代码

@page "/sql_server/crud/randtext"
@rendermode InteractiveServer
@using Microsoft.EntityFrameworkCore
@using MyProject.Models.SQLServer
@using MyProject.Data.SQLServer
@implements IAsyncDisposable
@inject IDbContextFactory<MyProject.Data.SQLServer.BlazorSQLServerContext> DbFactory

<!-- 客户端脚本部分 -->

@code {
    private SQLServerContext context = default!;
    private List<RandText> randText = new();

    protected override async Task OnInitializedAsync()
    {
        context = DbFactory.CreateDbContext();
        var sQLServerHelper = new SQLServerHelper(context);
        randText = await sQLServerHelper.GetRandTextsFromSqlROAsync("myStoredProcedure", null, null, "SEE_RECORDS");
    }

    public async ValueTask DisposeAsync()
    {
        await context.DisposeAsync();
    }
}

存储过程定义

CREATE PROCEDURE myStoredProcedure
    @id INT,
    @random_text VARCHAR(50),
    @key VARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @successful VARCHAR(20) = 'SUCCESSFUL';

    IF @key = 'SEE_RECORDS'
    BEGIN
        SELECT 
            RandText.id
            ,RandText.random_text
            ,RandText.dt_stamp
        FROM myDB.dbo.myTable AS RandText
        WHERE RandText.disable = 0
        ORDER BY RandText.dt_stamp DESC
    END
    ELSE
    BEGIN
        SELECT CONCAT('@key parameter value: ', '''', @key, '''', ' cannot be found.') SP_OUTPUT
    END
END

我之前参考过官方的示例,比如这种写法是可行的:

var user = new SqlParameter("user", "johndoe");
var blogs = await context.Blogs
.FromSql($"EXECUTE dbo.GetMostPopularBlogsForUser {user}")
.ToListAsync();

官方还提示:参数必须完全匹配存储过程定义,要注意参数顺序、类型对应,也可以考虑使用命名参数。

但我就是不知道为什么动态拼接的时候会出类型转换错误,手动指定索引就正常,有没有办法实现动态拼接的同时保证参数类型正确传递呢?麻烦各位指点一下,谢谢!


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:49:31