Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Core 3.1 Return value (int) from stored procedure

this returns -1, how can i get the actual return value from stored procedure?

here is my stored procedure

ALTER PROCEDURE [Production].[Select_TicketQuantity]
    @Ticket NVARCHAR(25),
    @Reference NVARCHAR(20)
AS
BEGIN

    declare @SQL nvarchar (4000)
    SET @SQL = 'select QARTCOL as Quantidade from D805DATPOR.GCARCCR1 where NCOLGIA = ' + @Ticket + ' AND NARTCOM = ''' + @Reference + ''''
    SET @SQL = N'select CONVERT(int,Quantidade) as Quantidade from OpenQuery(MACPAC, ''' + REPLACE(@SQL, '''', '''''') + ''')'
    PRINT @SQL
    EXEC (@SQL)

END   

C# code

int? quantity= 0;
try
{
    quantity= await _context.Database.ExecuteSqlRawAsync("EXEC Production.Select_TicketQuantity @p0, @p1", parameters: new[] { ticket, reference});
}
catch (Exception ex)
{
    _logger.LogError($"{ex}");
    return RedirectToPage("Index");
}
like image 722
Jackal Avatar asked Jan 07 '20 08:01

Jackal


People also ask

Does stored procedure have return value?

Stored procedures do not have a return value but can take a list with input, output, and input-output parameters.

Can we return from stored procedure?

You can use the return statement inside a stored procedure to return an integer status code (and only of integer type). By convention a return value of zero is used for success. If no return is explicitly set, then the stored procedure returns zero.

Can we use stored procedure in Entity Framework Core?

You can execute SP using FromSql method in EF Core in the same way as above, as shown below.


2 Answers

ExecuteSqlRawAsync returns the number of rows affected for inserts, updates and deletes (-1 for selects).

If you don't want to alter your SP to introduce the output parameter you can use SqlCommand. SqlCommand.ExecuteScalar() returns The first column of the first row in the result set:

using (var cmd = _context.Database.GetDbConnection().CreateCommand()) {
    cmd.CommandText = "[Production].[Select_TicketQuantity]";
    cmd.CommandType = System.Data.CommandType.StoredProcedure;
    if (cmd.Connection.State != System.Data.ConnectionState.Open) cmd.Connection.Open();
    cmd.Parameters.Add(new SqlParameter("Ticket", ticket));
    cmd.Parameters.Add(new SqlParameter("Reference", reference));
    quantity = (int)cmd.ExecuteScalar();
}
like image 94
AlbertK Avatar answered Oct 28 '22 04:10

AlbertK


To expand on @AlbertK's answer you can add an extension to the DatabaseFacade type to get different types of scalar values returned.

Make sure you are using the Microsoft.Data.SqlClient package rather than System.Data.SqlClient for your SqlParameter arguments otherwise you will receive a runtime exception. https://github.com/dotnet/efcore/issues/16812

public static class DatabaseFacadeExtensions
{
    public static async Task<TResult> ExecuteScalarAsync<TResult>(
        this DatabaseFacade database, 
        String commandText, 
        CommandType commandType, 
        params SqlParameter[] parameters)
    {
        TResult result;
        using (var cmd = database.GetDbConnection().CreateCommand())
        {
            cmd.CommandText = commandText;
            cmd.CommandType = commandType;
            if (cmd.Connection.State != System.Data.ConnectionState.Open) cmd.Connection.Open();
            cmd.Parameters.AddRange(parameters);
            result = (TResult)(await cmd.ExecuteScalarAsync());
        }
        return result;
    }
}
like image 25
BusyBee Avatar answered Oct 28 '22 04:10

BusyBee