Ich habe folgende Frage:
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
Dies kompiliert perfekt. Ich möchte diese Abfrage ausführen und den Rückgabewert erhalten. Mein Code ist unten:
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;
Hinweis: Die Ausnahmebehandlung wurde abgeschnitten, um den Code kurz zu halten. Jedes Mal, wenn ich zur letzten Zeile komme, wird null zurückgegeben. Was ist der logische Fehler bei diesem Code?
c#
sql
sql-server
GurdeepS
quelle
quelle
sqlcomm.Parameters["@b"]
mitretval
?retval.Direction = ParameterDirection.Output;
ParameterDirection.ReturnValue
sollte für den "Rückgabewert" der Prozedur verwendet werden, nicht für Ausgabeparameter. Es erhält den von der SQL-RETURN
Anweisung zurückgegebenen Wert (mit dem benannten Parameter@RETURN_VALUE
).Anstelle von
RETURN @b
dir sollteSET @b = something
Der Rückgabewertparameter ist übrigens immer ein
int
String.quelle
Ich hatte jede Menge Probleme mit dem Rückgabewert, also habe ich am Ende nur Sachen ausgewählt.
Die Lösung bestand darin, das Ergebnis am Ende auszuwählen und das Abfrageergebnis in Ihrer Funktion zurückzugeben.
In meinem Fall habe ich eine Existenzprüfung durchgeführt:
IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE @RoleName = RoleName)) SELECT 1 ELSE SELECT 0
Dann
using (SqlConnection cnn = new SqlConnection(ConnectionString)) { SqlCommand cmd = cnn.CreateCommand(); cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "RoleExists"; return (int) cmd.ExecuteScalar() }
Sie sollten in der Lage sein, dasselbe mit einem Zeichenfolgenwert anstelle eines int zu tun.
quelle
Dies baut auf den Antworten von Joel und Mehrdad auf: Sie binden niemals den Parameter des
retval
an dassqlcommand
. Du brauchst einsqlcomm.Parameters.Add(retval);
und um sicherzustellen, dass Sie den Befehl ausführen
sqlcomm.ExecuteNonQuery();
Ich bin mir auch nicht sicher, warum Sie 2 Rückgabewertzeichenfolgen (
returnValue
undretunvalue
) haben.quelle
Sie sagen, Ihr SQL wird gut kompiliert, aber ich verstehe: Muss die skalare Variable "@Password" deklarieren.
Außerdem versuchen Sie, ein varchar (@b) von Ihrer gespeicherten Prozedur zurückzugeben, aber gespeicherte SQL Server-Prozeduren können nur Ganzzahlen zurückgeben.
Wenn Sie die Prozedur ausführen, wird folgende Fehlermeldung angezeigt:
'Die Konvertierung ist fehlgeschlagen, wenn der Varchar-Wert' x 'in den Datentyp int konvertiert wurde.'
quelle
Wenn wir einen Wert aus der gespeicherten Prozedur ohne select-Anweisung zurückgeben. Wir müssen die Befehle "ParameterDirection.ReturnValue" und "ExecuteScalar" verwenden, um den Wert abzurufen.
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); }
Wir erhalten den zurückgegebenen Wert von SP "IsEmailExists" unter Verwendung der obigen c # -Funktion.
quelle
Dieser SP sieht sehr seltsam aus. Es wird nicht geändert, was an @b übergeben wird. Und nirgends im SP weisen Sie @b etwas zu. Und @Password ist nicht definiert, sodass dieser SP überhaupt nicht funktioniert.
Ich würde vermuten, dass Sie tatsächlich @Password zurückgeben oder SET @b = (SELECT ...) haben möchten.
Viel einfacher ist es, wenn Sie Ihren SP auf ändern (Hinweis, kein OUTPUT-Parameter):
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
Dann kann Ihr Code cmd.ExecuteScalar verwenden und das Ergebnis erhalten.
quelle
Es gibt zwei Dinge zu beheben. Richten Sie zuerst die gespeicherte Prozedur ein, um den Wert im Ausgabeparameter (nicht Rückgabeparameter) zu speichern.
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
Dies wird aber das Passwort in @b und Sie erhalten es als Rückgabeparameter. Um es in Ihr C # zu bekommen, gehen Sie wie folgt vor:
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(); }
quelle
Vielleicht hilft das.
Datenbankskript:
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
Anwendungskonfigurationsdatei:
<?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>
Datenzugriffsschicht (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; } } }
Implementierung :
BLL.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"), new SqlParameter("neupassword","Moro$ilka"), new SqlParameter("neuposition","Moroz") );
quelle
Hier gibt es mehrere Probleme:
sqlcomm
wurde nie hingerichtet. Sie müssen aufrufensqlcomm.ExecuteNonQuery();
, um Ihren Befehl auszuführen.Hier ist eine Lösung mit OUTPUT-Parametern. Dies wurde getestet mit:
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; }
quelle
sqlcomm.Parameters.Add("@b", SqlDbType.VarChar,50);
hier 50 die Länge ist.Sie haben das Konzept der Rückgabewert- und Ausgabevariablen verwechselt. 1- Ausgangsvariable:
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();
quelle
Angenommen , Sie müssen passieren
Username
undPassword
zu gespeicherten Prozedur und wissen , ob die Anmeldung erfolgreich ist oder nicht , und prüfen Sie, ob ein Fehler in aufgetreten ist 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; }
Ihre Verbindungszeichenfolge 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>
Und hier ist die gespeicherte Prozedur als Referenz
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 EMPNAME=@Username AND EMPPASSWORD=@Password) 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
quelle
Wenn Sie verwenden
cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
Sie müssen dann sicherstellen, dass Ihre gespeicherte Prozedur hat
return @RETURN_VALUE;
am Ende der gespeicherten Prozedur.
quelle
Der Wert, den Sie abrufen möchten, ist kein Rückgabewert, sondern ein Ausgabeparameter. Sie müssen die Parameterrichtung in Ausgabe ändern.
SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar); retval.Direction = ParameterDirection.Output; command.ExecuteNonquery(); string retunvalue = (string)sqlcomm.Parameters["@b"].Value;
quelle
Für .net Core 3.0 und Dapper:
Wenn Ihre gespeicherte Prozedur Folgendes zurückgibt:
select ID, FILE_NAME from dbo.FileStorage where ID = (select max(ID) from dbo.FileStorage);
Dann in c #:
var data = (_dbConnection.Query<FileUploadQueryResponse> ("dbo.insertFile", whateverParameters, commandType: CommandType.StoredProcedure)).ToList(); var storedFileName = data[0].FILE_NAME; var id = data[0].ID;
Wie Sie sehen können, können Sie eine einfache Klasse definieren, um die tatsächlichen Werte aus der Standard-Rückgabestruktur von dapper abzurufen (mit der ich nicht arbeiten konnte):
public class FileUploadQueryResponse { public string ID { get; set; } public string FILE_NAME { get; set; } }
quelle
Diese Codezeile gibt den von SQL Server zurückgegebenen Wert von Store StoredProcedure zurück
cmd.Parameters.Add("@id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue; cmd.ExecuteNonQuery();
Atfer Die Ausführung des Abfragewerts wird von SP zurückgegeben
id = (int)cmd.Parameters["@id"].Value;
quelle