Получение возвращаемого значения из хранимой процедуры в C # - PullRequest
63 голосов
/ 01 апреля 2009

У меня следующий запрос:

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

Это прекрасно компилируется.

В C # я хочу выполнить этот запрос и получить возвращаемое значение.

Мой код как ниже:

  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;

Примечание: обработка исключений сокращена, чтобы код был коротким. Каждый раз, когда я добираюсь до последней строки, возвращается ноль. В чем логическая ошибка с этим кодом?

Спасибо

Ответы [ 14 ]

86 голосов
/ 01 апреля 2009

Mehrdad делает несколько хороших замечаний, но главное, что я заметил, - вы никогда не запускаете запрос ...

SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["@b"].Value;
61 голосов
/ 01 апреля 2009
retval.Direction = ParameterDirection.Output;

ParameterDirection.ReturnValue следует использовать для «возвращаемого значения» процедуры, а не для вывода параметров. Он получает значение, возвращаемое оператором SQL RETURN (с параметром @RETURN_VALUE).

Вместо RETURN @b вы должны SET @b = something

Кстати, параметр возвращаемого значения всегда int, а не строка.

10 голосов
/ 01 апреля 2009

У меня были тонны проблем с возвращаемым значением, поэтому я просто выбрал вещи в конце.

Решением было просто выбрать результат в конце и вернуть результат запроса в функции.

В моем случае я делал проверку на существование:

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

Тогда

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

Вы должны быть в состоянии сделать то же самое со строковым значением вместо целого.

5 голосов
/ 16 декабря 2010

Это основано на ответах Джоэла и Мехрдада : вы никогда не привязываете параметр retval к sqlcommand. Вам нужно

sqlcomm.Parameters.Add(retval);

и убедитесь, что вы запускаете команду

sqlcomm.ExecuteNonQuery();

Я также не уверен, почему у вас есть 2 строки возвращаемых значений (returnValue и retunvalue).

4 голосов
/ 28 декабря 2017

Когда мы возвращаем значение из хранимой процедуры без оператора выбора. Нам нужно использовать команды «ParameterDirection.ReturnValue» и «ExecuteScalar», чтобы получить значение.

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

в 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);
        }

Мы получаем возвращенное значение SP "IsEmailExists", используя вышеуказанную функцию c #.

4 голосов
/ 01 апреля 2009

Вы говорите, что ваш SQL компилируется нормально, но я получаю: Должен объявить скалярную переменную "@Password".

Также вы пытаетесь вернуть varchar (@b) из вашей хранимой процедуры, но хранимые процедуры SQL Server могут возвращать только целые числа.

Когда вы запустите процедуру, вы получите сообщение об ошибке:

'Сбой преобразования при преобразовании значения varchar' x 'в тип данных int.'

3 голосов
/ 01 апреля 2017

Может быть, это поможет.

Сценарий базы данных:

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

Файл конфигурации приложения:

<?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>

Уровень доступа к данным (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();


        }


    }
}

Уровень бизнес-логики (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;

        }

    }
}

Реализация:

BLL.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"),
                 new SqlParameter("neupassword","Moro$ilka"),
                 new SqlParameter("neuposition","Moroz")
                 );
3 голосов
/ 09 февраля 2017

Здесь несколько проблем:

  1. Это невозможно. Вы пытаетесь вернуть варчар. Хранится Возвращаемые значения процедуры могут быть только целочисленными выражениями. Увидеть официальная ВОЗВРАТНАЯ документация: https://msdn.microsoft.com/en-us/library/ms174998.aspx.
  2. Ваш sqlcomm никогда не был казнен. Вы должны позвонить sqlcomm.ExecuteNonQuery(); чтобы выполнить вашу команду.

Вот решение, использующее параметры OUTPUT. Это было проверено с:

  • 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 голосов
/ 01 апреля 2009

Этот ИП выглядит очень странно. Он не изменяет то, что передается в @b. И нигде в SP вы ничего не назначаете @b. И @Password не определен, поэтому этот SP не будет работать вообще.

Я думаю, вы действительно хотите вернуть @Password или иметь SET @b = (SELECT ...)

Гораздо проще будет, если вы измените свой SP на (обратите внимание, без параметра 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

Тогда ваш код может использовать cmd.ExecuteScalar и получить результат.

2 голосов
/ 09 июня 2015

Есть две вещи, которые нужно исправить. Сначала настройте хранимую процедуру для сохранения значения в выходном (не возвращаемом) параметре.

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

Это будет пароль, кроме @b, и вы получите его в качестве возвращаемого параметра. Затем, чтобы получить это в вашем C #, сделайте это:

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();
     }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...