在 .NET Core 3.1 中执行存储过程

Posted

技术标签:

【中文标题】在 .NET Core 3.1 中执行存储过程【英文标题】:Execute Stored Procedure in .NET Core 3.1 【发布时间】:2021-11-05 17:42:29 【问题描述】:

我正在尝试在 ASP.NET Core 3.1 中运行 SQL Server 2019 存储过程,但无法正常运行。

我已经实现了存储库布局模式,并使用以下命令获取了数据库对象:

Scaffold-DbContext "Server="";Database="";User ID="";Password="";" Microsoft.EntityFrameworkCore.SqlServer -OutputDir database

执行程序时,如果结果是用户存在于数据库中,则应该返回1,否则返回0。总是返回1给变量“exists”的问题,但我想我是不执行存储过程(它有一个输出参数)或者我不知道该过程是否需要以某种方式导入到应用程序中。

程序示例:

CREATE PROCEDURE [dbo].[LOGIN]
    @LOGIN    VARCHAR(50),  
    @PASSWORD VARCHAR(50),
    @EXIT     INT OUTPUT
BEGIN
    IF EXISTS (SELECT USER_APP FROM USERS 
               WHERE USER_APP = @LOGIN AND PASSWORD = @PASSWORD)
    BEGIN
        SET @EXIT = 1
        RETURN @EXIT
    END

    SET @EXIT = 0
    RETURN @EXIT
END

程序:

private readonly dbContext _context;

public UsuariosRepository(dbContext context)

    _context = context;


public async Task<bool> lOG(string user, string password)
 
    try
    
        int exists= await _context.Database.ExecuteSqlRawAsync("EXECUTE Login 0,1", user, password);

        return exists > 0;
    
    catch (Exception ex)
    
        throw ex;
    

根据我在中找到的教程,用我目前拥有的代码更新问题:

https://erikej.github.io/efcore/2020/11/02/ef-core-sproc-return-value.html

var retcode = new SqlParameter

    ParameterName = "0",
    SqlDbType = System.Data.SqlDbType.Int,
    Direction = System.Data.ParameterDirection.Output,
    Value=0
;
var result =  _context.Database.ExecuteSqlRaw("EXEC Login 0,1,2", usuario, password,retcode);

int returnValue = (int)retcode.Value;

即使进行了更改,它对我也不起作用,它会显示以下错误。

Unable to cast object of type 'System.DBNull' to type 'System.Int32

非常感谢您的帮助。

教程

【问题讨论】:

entityframeworktutorial.net/efcore/… 我对这些命令进行了测试,但它表明它们在 NetCore 3.1 中已被弃用。谢谢 我发现的另一个不一致之处,在您的 store procedure 中有 RETURN 它不应该返回任何内容,因为在 store procedure 中我们必须使用 SELECT 声明,我怀疑您的 sp可以以这种方式返回10,另一件事是您已经定义了3 个参数但传递了2 个应该引发期望的参数,我认为根据您的情况,您应该在sp 正文中写DECLARE @EXIT INT 而不是定义它。 有 3 种方法可以从存储过程中返回信息:返回值 - 应该只用于指示操作的状态,而 not 用于返回业务逻辑,如“用户没有/ 不存在”,OUTPUT 参数发送单个值或一组值,选择一个结果集。你用错了.. 旁白:请告诉您的新公司停止以纯文本形式存储密码! 【参考方案1】:

要按原样使用您的存储过程,您可能应该连接到输出参数。请注意,除了“生成 SqlConnection/命令的东西”之外,这并没有真正使用* EF Core:


string user = "bob";
string password = Convert.ToBase64tring(Sha256Hash("secret", "mmmmsalty"));// you salt and hash your passwords, right??


using var cmd = _context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "[dbo].[LOGIN]";

//common
cmd.CommandType = CommandType.StoredProcedure;
if (cmd.Connection.State != ConnectionState.Open) cmd.Connection.Open();
cmd.Parameters.Add(new SqlParameter("@LOGIN", SqlDbType.VarChar)  Value = user );
cmd.Parameters.Add(new SqlParameter("@PASSWORD", SqlDbType.VarChar)  Value = password );
cmd.Parameters.Add(new SqlParameter("@EXIT", SqlDbType.Int)  Direction = ParameterDirection.Output );

cmd.ExecuteNonQuery();

var userExists = (int)cmd.Parameters["@EXIT"].Value == 1;

记得添加必要的usings..

*(AFAIA,没有方法可以;即使看起来像使用 EF Core 的方法也只是获取其 SQLBuilder 并构建一个调用存储过程的命令)

【讨论】:

【参考方案2】:

ExecuteSqlRawAsync 返回插入、更新和删除受影响的行数(-1 表示选择)。

我建议您更改您的 SP 以删除输出参数,而是使用 SqlCommand. SqlCommand.ExecuteScalar() 返回结果集中第一行的第一列:

using (var cmd = _context.Database.GetDbConnection().CreateCommand()) 
    cmd.CommandText = "[dbo].[LOGIN]";
    cmd.CommandType = System.Data.CommandType.StoredProcedure;
    if (cmd.Connection.State != System.Data.ConnectionState.Open) cmd.Connection.Open();
    cmd.Parameters.Add(new SqlParameter("LOGIN", user));
    cmd.Parameters.Add(new SqlParameter("PASSWORD", password));
    exists = (int)cmd.ExecuteScalar();

只需将@EXIT 声明为不是输出,例如:

CREATE PROCEDURE [dbo].[LOGIN]
    @LOGIN      VARCHAR(50),    
    @PASSWORD   VARCHAR(50) 

    DECLARE @EXIT INT

并将 CREATE 替换为 ALTER 以编辑存储过程。

【讨论】:

以上是关于在 .NET Core 3.1 中执行存储过程的主要内容,如果未能解决你的问题,请参考以下文章

如何从 ASP.NET Core 3.1 中的存储库类创建确认电子邮件回调

在 ASP.NET MVC Core(C#) 中执行 Oracle 存储过程 (PL/SQL)

如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?

包含在FromSqlRaw和EF Core 3.1中的存储过程中

在 cookie 中存储 JWT 令牌后,如何在 ASP.NET Core 3.1 中破坏该 cookie 并获取信息

如何使用 FromSqlRaw Entity Framework Core 3.1 从存储过程中返回多个 SELECT 集