Ottieni il valore del parametro di output di una procedura memorizzata usando EF Core?

Sto usando il core Asp.net e il core EF nella mia applicazione. Fondamentalmente voglio ottenere più set di risultati da una singola stored procedure. Ho provato a cercarlo negli ultimi 2 giorni senza tanta fortuna. Ho cercato di capire un lavoro per risolverlo ..

Questa è la mia stored procedure:

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[usp_CustomerAll_sel] @SomeOutput int OUT AS BEGIN SET NOCOUNT ON; SELECT * FROM [dbo].[Customer] SELECT @SomeOutput = @@rowcount + 25 --This number 25 is a variable from a complex query but always an integer END 

Ho due record in quella tabella, quindi in pratica dovrebbe restituire una tabella di tipo di cliente e il parametro di output dovrebbe restituire 27 ..

Ora dal mio codice .net quello che ho provato finora

 [HttpGet] public async Task<Tuple<IEnumerable, int>> GetAllCustomer() { var votesParam = new SqlParameter { ParameterName = "SomeOutput", Value = -1, Direction = ParameterDirection.Output }; var y = await _customerContext.Customers.FromSql("usp_CustomerAll_sel @SomeOutput out", votesParam).ToArrayAsync(); return new Tuple<IEnumerable, int>(y, (int)votesParam.Value); } 

Sopra uno mi restituisce la lista ma non sto ottenendo il valore del parametro di output da DB .(int)votesParam.Value sta mostrando null

Ora se uso ExecuteNonQueryAsync , allora ottengo il parametro di output ma non i dati reali

 private async Task ExecuteStoredProc() { DbCommand cmd = _customerContext.Database.GetDbConnection().CreateCommand(); cmd.CommandText = "dbo.usp_CustomerAll_sel"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter("@SomeOutput", SqlDbType.BigInt) { Direction = ParameterDirection.Output, Value = -1 }); if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } await cmd.ExecuteNonQueryAsync(); long SomeOutput = (long)cmd.Parameters["@SomeOutput"].Value; } 

C’è un modo per ottenere sia il set di risultati che il parametro di output e tornare come una tupla?

Quando ho appena inserito il valore hard coded, sembra che sia

 [HttpGet] public async Task<Tuple<IEnumerable, int>> GetAllCustomer() { var votesParam = new SqlParameter { ParameterName = "SomeOutput", Value = -1, Direction = ParameterDirection.Output }; var y = await _customerContext.Customers.FromSql("usp_CustomerAll_sel @SomeOutput out", votesParam).ToArrayAsync(); return new Tuple<IEnumerable, int>(y, **25**); } 

E come risultato

 {"item1":[{"customerId":1,"customerName":"Cus1"},{"customerId":2,"customerName":"Cus2"}],"item2":27} 

Fondamentalmente questo è quello che sto cercando … Qualsiasi aiuto?

Questo dovrebbe funzionare. Questa volta ho riempito solo un DataTable, ma puoi riempire un DataSet con multipli DataTable

 using (SqlConnection connection = new SqlConnection(_customerContext.Database.Connection.ConnectionString)) { SqlCommand cmd = new SqlCommand("dbo.usp_CustomerAll_sel", connection); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter("@SomeOutput", SqlDbType.BigInt) { Direction = ParameterDirection.Output, Value = -1 }); if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } connection.Open(); SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); adapter.Fill(dt); long SomeOutput = (long)cmd.Parameters["@SomeOutput"].Value; connection.Close(); } 

Poiché non è ansible utilizzare SqlDataAdapter in .net core, è ansible utilizzare una libreria di terze parti per ottenere lo stesso risultato, ad esempio NReco.Data , in realtà, il codice è piuttosto simile.

In EF Core non è ansible restituire ancora tipi ad-hoc da query SQL non elaborate (funzionano su questo), quindi per prima cosa è necessario un allenamento per questo problema, aggiungere questa class al progetto:

  using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; namespace Microsoft.EntityFrameworkCore { public static class RDFacadeExtensions { public static RelationalDataReader ExecuteSqlQuery(this DatabaseFacade databaseFacade, string sql, params object[] parameters) { var concurrencyDetector = databaseFacade.GetService(); using (concurrencyDetector.EnterCriticalSection()) { var rawSqlCommand = databaseFacade .GetService() .Build(sql, parameters); return rawSqlCommand .RelationalCommand .ExecuteReader( databaseFacade.GetService(), parameterValues: rawSqlCommand.ParameterValues); } } } } 

Quindi puoi chiamare il metodo seguente e ottenere l’OUTPUT da te SP, ecco un esempio:

  var _sMsg = new SqlParameter("sMsg", "") { Direction = ParameterDirection.Output, DbType = DbType.String, Size = 500 }; var sql = "exec sp_foo @sUserId, @sMsg OUTPUT"; var dr = _ctx.Database.ExecuteSqlQuery(sql, _sUserID, _sMsg); //here you can retrive your table while (dr.DbDataReader.Read()) { var bar = dr.DbDataReader[0].ToString(); } //here is your OUTPUT return _sMsg.Value.ToString(); 

Ecco un esempio di come è ansible ottenere più set di risultati da una stored procedure, se si è a posto con ADO.NET:

Restituisce più recordset dal processo memorizzato in C #

Bisogna però abbandonare il parametro di output in questo caso.