2009-04-01 43 views
57

Ho la seguente query:Ottenere valore di ritorno dalla stored procedure in C#

set ANSI_NULLS ON 
set QUOTED_IDENTIFIER ON 
go 

ALTER PROCEDURE [dbo].[Validate] 
@a varchar(50), 
@b varchar(50) output 

AS 

SET @Password = 
(SELECT Password 
FROM dbo.tblUser 
WHERE Login = @a) 

RETURN @b 
GO 

Questo compila perfettamente bene.

In C#, voglio eseguire questa query e ottenere il valore restituito.

Il mio codice è il seguente:

SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString()); 
     System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn); 

     string returnValue = string.Empty; 

     try 
     { 
      SqlConn.Open(); 
      sqlcomm.CommandType = CommandType.StoredProcedure; 

      SqlParameter param = new SqlParameter("@a", SqlDbType.VarChar); 
      param.Direction = ParameterDirection.Input; 
      param.Value = Username; 
      sqlcomm.Parameters.Add(param); 



      SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar); 
      retval.Direction = ParameterDirection.ReturnValue; 


      string retunvalue = (string)sqlcomm.Parameters["@b"].Value; 

Nota: Gestione delle eccezioni taglio per mantenere il codice funzione. Ogni volta che arrivo all'ultima riga, viene restituito un valore nullo. Qual è l'errore logico con questo codice?

Grazie

risposta

59
retval.Direction = ParameterDirection.Output; 

ParameterDirection.ReturnValue dovrebbero essere utilizzati per il "valore di ritorno" del procedimento, non parametri di output. Ottiene il valore restituito dall'istruzione SQL RETURN (con il parametro denominato @RETURN_VALUE).

Invece di RETURN @b si dovrebbe SET @b = something

Tra l'altro, il valore del parametro di ritorno è sempre int, non stringa.

82

Mehrdad fa alcuni buoni punti, ma la cosa principale che ho notato è che si non esegue la query ...

SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar); 
retval.Direction = ParameterDirection.ReturnValue; 
sqlcomm.ExecuteNonQuery(); // MISSING 
string retunvalue = (string)sqlcomm.Parameters["@b"].Value; 
4

detto che si SQL compila bene, ma ottengo: Deve dichiarare la scalari variabile "@Password".

Inoltre, si sta tentando di restituire un varchar (@b) dalla stored procedure, ma le stored procedure di SQL Server possono restituire solo numeri interi.

Quando si esegue la procedura che si sta per ottenere l'errore:

'Conversione non riuscita durante la conversione del valore varchar 'x' per tipo di dati int.'

3

Questo SP sembra molto strano. Non modifica ciò che viene passato a @b. E da nessuna parte nella SP si assegna qualcosa a @b. E @Password non è definito, quindi questo SP non funzionerà affatto.

direi che realmente desidera tornare @Password, o di aver SET @ b = (SELECT ...)

Molto più semplice sarà se si modifica il SP a (nota, nessun parametro OUTPUT):

set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go 

ALTER PROCEDURE [dbo].[Validate] @a varchar(50) 

AS 

SELECT TOP 1 Password FROM dbo.tblUser WHERE Login = @a 

Quindi, il codice può utilizzare cmd.ExecuteScalar e ricevere il risultato.

8

Avevo un sacco di problemi con il valore restituito, quindi alla fine ho scelto solo cose.

La soluzione era solo per selezionare il risultato alla fine e restituire il risultato della query nella tua funzione.

Nel mio caso stavo facendo un controllo esiste:

IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE @RoleName = RoleName)) 
    SELECT 1 
ELSE 
    SELECT 0 

Poi

using (SqlConnection cnn = new SqlConnection(ConnectionString)) 
{ 
    SqlCommand cmd = cnn.CreateCommand(); 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.CommandText = "RoleExists"; 
    return (int) cmd.ExecuteScalar() 
} 

si dovrebbe essere in grado di fare la stessa cosa con un valore di stringa invece di un int.

+0

molto utile per me.Grazie –

5

Questa è la costruzione su Joel's e Mehrdad's risposte: non si è mai vincolante il parametro della retval al sqlcommand. Avete bisogno di un

sqlcomm.Parameters.Add(retval); 

e per assicurarsi che si sta eseguendo il comando

sqlcomm.ExecuteNonQuery(); 

Io non sono anche sicuro perché si hanno 2 stringhe valore di ritorno (returnValue e retunvalue).

2

Hai confuso il concetto del valore di ritorno e della variabile di uscita. variabile 1- uscita:

Database----->: 
create proc MySP 
@a varchar(50), 
@b varchar(50) output 
AS 
SET @Password = 
(SELECT Password 
FROM dbo.tblUser 
WHERE Login = @a) 

C# ----->: 

SqlConn.Open(); 
sqlcomm.CommandType = CommandType.StoredProcedure; 

SqlParameter param = new SqlParameter("@a", SqlDbType.VarChar); 
param.Direction = ParameterDirection.Input;//This is optional because Input is the default 

param.Value = Username; 
sqlcomm.Parameters.Add(param); 

SqlParameter outputval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar); 
outputval .Direction = ParameterDirection.Output//NOT ReturnValue; 


string outputvalue = sqlcomm.Parameters["@b"].Value.ToString(); 
+0

Mi piace questo ma sembra che "SET @Password" dovrebbe essere "SET @b" –

0

Si supponga di dover passare Username e Password a stored procedure e sapere se login è successo o meno e verificare se si è verificato alcun errore nella stored procedure.

public bool IsLoginSuccess(string userName, string password) 
{ 
    try 
    { 
     SqlConnection SQLCon = new SqlConnection(WebConfigurationManager.ConnectionStrings["SqlConnector"].ConnectionString); 
     SqlCommand sqlcomm = new SqlCommand(); 
     SQLCon.Open(); 
     sqlcomm.CommandType = CommandType.StoredProcedure; 
     sqlcomm.CommandText = "spLoginCheck"; // Stored Procedure name 
     sqlcomm.Parameters.AddWithValue("@Username", userName); // Input parameters 
     sqlcomm.Parameters.AddWithValue("@Password", password); // Input parameters 

     // Your output parameter in Stored Procedure   
     var returnParam1 = new SqlParameter 
     { 
      ParameterName = "@LoginStatus", 
      Direction = ParameterDirection.Output, 
      Size = 1      
     }; 
     sqlcomm.Parameters.Add(returnParam1); 

     // Your output parameter in Stored Procedure 
     var returnParam2 = new SqlParameter 
     { 
      ParameterName = "@Error", 
      Direction = ParameterDirection.Output, 
      Size = 1000      
     }; 

     sqlcomm.Parameters.Add(returnParam2); 

     sqlcomm.ExecuteNonQuery(); 
     string error = (string)sqlcomm.Parameters["@Error"].Value; 
     string retunvalue = (string)sqlcomm.Parameters["@LoginStatus"].Value;      
    } 
    catch (Exception ex) 
    { 

    } 
    return false; 
} 

la stringa di connessione in Web.Config

<connectionStrings> 
    <add name="SqlConnector" 
     connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Databasename;User id=yourusername;Password=yourpassword" 
     providerName="System.Data.SqlClient" /> 
    </connectionStrings> 

Ed ecco la stored procedure per riferimento

CREATE PROCEDURE spLoginCheck 
    @Username Varchar(100), 
    @Password Varchar(100) , 
    @LoginStatus char(1) = null output, 
    @Error Varchar(1000) output 
AS 
BEGIN 

    SET NOCOUNT ON; 
    BEGIN TRY 
     BEGIN 

      SET @Error = 'None' 
      SET @LoginStatus = '' 

      IF EXISTS(SELECT TOP 1 * FROM EMP_MASTER WHERE [email protected] AND [email protected]) 
      BEGIN 
       SET @LoginStatus='Y' 
      END 

      ELSE 
      BEGIN 
       SET @LoginStatus='N' 
      END 

     END 
    END TRY 

    BEGIN CATCH 
     BEGIN   
      SET @Error = ERROR_MESSAGE() 
     END 
    END CATCH 
END 
GO 
2

Ci sono due cose da sistemare su questo. Per prima cosa impostare la procedura memorizzata per memorizzare il valore nel parametro di uscita (non di ritorno).

set ANSI_NULLS ON 
set QUOTED_IDENTIFIER ON 
go 

ALTER PROCEDURE [dbo].[Validate] 
@a varchar(50), 
@b varchar(50) output 

AS 

SET @b = 
(SELECT Password 
FROM dbo.tblUser 
WHERE Login = @a) 

RETURN 
GO 

Questa volontà, ma la password nel @b e si otterrà come parametro di ritorno. Poi per farlo nel vostro C# fare questo:

SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString()); 
    System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn); 

    string returnValue = string.Empty; 

    try 
    { 
     SqlConn.Open(); 
     sqlcomm.CommandType = CommandType.StoredProcedure; 

     SqlParameter param = new SqlParameter("@a", SqlDbType.VarChar, 50); 
     param.Direction = ParameterDirection.Input; 
     param.Value = Username; 
     sqlcomm.Parameters.Add(param); 



     SqlParameter retval = new SqlParameter("@b", SqlDbType.VarChar, 50); 
     retval.Direction = ParameterDirection.ReturnValue; 
     sqlcomm.Parameters.Add(retval); 

     sqlcomm.ExecuteNonQuery(); 
     SqlConn.Close(); 

     string retunvalue = retval.Value.ToString(); 
    } 
+0

Questo dovrebbe essere nella parte superiore. L'unica risposta veramente completa! – Seth

1

quando si utilizza

cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue; 

è necessario quindi garantire la vostra stored procedure ha

return @RETURN_VALUE; 

al termine della stored procedure.

3

ci sono molteplici problemi qui:

  1. non è possibile. Stai cercando di restituire un varchar. I valori di ritorno della stored procedure possono essere solo espressioni intere.Vedere la documentazione di ritorno ufficiale : https://msdn.microsoft.com/en-us/library/ms174998.aspx.
  2. Il tuo sqlcomm non è mai stato eseguito. Devi chiamare lo sqlcomm.ExecuteNonQuery(); per eseguire il tuo comando.

Ecco una soluzione che utilizza parametri di output. Questo è stato testato con:

  • di Windows Server 2012
  • .NET v4.0.30319
  • C# 4,0
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[Validate] 
    @a varchar(50), 
    @b varchar(50) OUTPUT 
AS 
BEGIN 
    DECLARE @b AS varchar(50) = (SELECT Password FROM dbo.tblUser WHERE Login = @a) 
    SELECT @b; 
END 
SqlConnection SqlConn = ... 
var sqlcomm = new SqlCommand("Validate", SqlConn); 

string returnValue = string.Empty; 

try 
{ 
    SqlConn.Open(); 
    sqlcomm.CommandType = CommandType.StoredProcedure; 

    SqlParameter param = new SqlParameter("@a", SqlDbType.VarChar); 
    param.Direction = ParameterDirection.Input; 
    param.Value = Username; 
    sqlcomm.Parameters.Add(param); 

    SqlParameter output = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar); 
    ouput.Direction = ParameterDirection.Output; 

    sqlcomm.ExecuteNonQuery(); // This line was missing 

    returnValue = output.Value.ToString(); 

    // ... the rest of code 

} catch (SqlException ex) { 
    throw ex; 
} 
3

Può essere questo sarà di aiuto.

sceneggiatura

Database:

USE [edata] 
GO 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 


CREATE PROCEDURE [dbo].[InsertNewUser](
@neuname NVARCHAR(255), 
@neupassword NVARCHAR(255), 
@neuposition NVARCHAR(255) 
) 

AS 

BEGIN 

BEGIN TRY 

DECLARE @check INT; 

SET @check = (SELECT count(eid) FROM eusers WHERE euname = @neuname); 

IF(@check = 0) 

INSERT INTO eusers(euname,eupassword,eposition) 
VALUES(@neuname,@neupassword,@neuposition); 

DECLARE @lastid INT; 

SET @lastid = @@IDENTITY; 

RETURN @lastid; 


END TRY 


BEGIN CATCH 

SELECT ERROR_LINE() as errline, 
     ERROR_MESSAGE() as errmessage, 
     ERROR_SEVERITY() as errsevirity 

END CATCH 

END 

Applicazione file di configurazione:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 

    <appSettings> 
    <add key="conStr" value="Data Source=User\SQLEXPRESS;Initial Catalog=edata;Integrated Security=True"/> 
    </appSettings> 
</configuration> 

strato di accesso ai dati (DAL):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Configuration; 
using System.Data; 
using System.Data.SqlClient; 
namespace DAL 
{ 
    public static class DAL 
    { 
     public static SqlConnection conn; 

     static DAL() 
     { 


      conn = new SqlConnection(ConfigurationManager.AppSettings["conStr"].ToString()); 
      conn.Open(); 


     } 


    } 
} 

Business Logic Layer (BLL):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Data; 
using System.Data.SqlClient; 
using DAL; 
namespace BLL 
{ 
    public static class BLL 
    { 


     public static int InsertUser(string lastid, params SqlParameter[] coll) 
     { 

      int lastInserted = 0; 

      try 
      { 


       SqlCommand comm = new SqlCommand(); 

       comm.Connection = DAL.DAL.conn; 


       foreach (var param in coll) 
       { 

        comm.Parameters.Add(param); 

       } 

       SqlParameter lastID = new SqlParameter(); 
       lastID.ParameterName = lastid; 
       lastID.SqlDbType = SqlDbType.Int; 
       lastID.Direction = ParameterDirection.ReturnValue; 

       comm.Parameters.Add(lastID); 

       comm.CommandType = CommandType.StoredProcedure; 

       comm.CommandText = "InsertNewUser"; 

       comm.ExecuteNonQuery(); 

       lastInserted = (int)comm.Parameters[lastid].Value; 

      } 

      catch (SqlException ex) 
      { 


      } 

      finally { 

       if (DAL.DAL.conn.State != ConnectionState.Closed) { 

        DAL.DAL.conn.Close(); 
       } 

      }   

      return lastInserted; 

     } 

    } 
} 

Implementazione:

BLL.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"), 
       new SqlParameter("neupassword","Moro$ilka"), 
       new SqlParameter("neuposition","Moroz") 
       ); 
1

Quando torniamo un valore da stored procedure, senza select. Abbiamo bisogno di utilizzare il comando "ParameterDirection.ReturnValue" e "ExecuteScalar" per ottenere il valore.

CREATE PROCEDURE IsEmailExists 
    @Email NVARCHAR(20) 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- Insert statements for procedure here 
    IF EXISTS(SELECT Email FROM Users where Email = @Email) 
    BEGIN 
     RETURN 0 
    END 
    ELSE 
    BEGIN 
     RETURN 1 
    END 
END 

in C#

GetOutputParaByCommand("IsEmailExists") 

public int GetOutputParaByCommand(string Command) 
     { 
      object identity = 0; 
      try 
      { 
       mobj_SqlCommand.CommandText = Command; 
       SqlParameter SQP = new SqlParameter("returnVal", SqlDbType.Int); 
       SQP.Direction = ParameterDirection.ReturnValue; 
       mobj_SqlCommand.Parameters.Add(SQP); 
       mobj_SqlCommand.Connection = mobj_SqlConnection; 
       mobj_SqlCommand.ExecuteScalar(); 
       identity = Convert.ToInt32(SQP.Value); 
       CloseConnection(); 
      } 
      catch (Exception ex) 
      { 

       CloseConnection(); 
      } 
      return Convert.ToInt32(identity); 
     } 

otteniamo il valore restituito di SP "IsEmailExists" utilizzando la funzione di cui sopra C#.

Problemi correlati