Michael Billingham
Michael Billingham

Reputation: 117

Retrieve return value from stored procedure

I have written a table-valued parameter stored procedure, It returns the Id that was inserted. If I run it from a query inside SSMS, it works and returns the value correctly.

When I call the procedure from code, it runs, and inserts the data but does not set the return parameter I have added and marked as a return parameter.

What am I doing wrong here?

SP:

ALTER PROCEDURE [dbo].[InsertUpdateMeeting] 
    -- Add the parameters for the stored procedure here
    @Meeting MeetingsTableType READONLY,
    @Area AreasTableType READONLY,
    @MeetingLocation MeetingLocationsTableType READONLY

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    -- Insert statements for procedure here
    DECLARE @MeetingId int = 0;
    DECLARE @AreaId int;
    DECLARE @MeetingLocationId int;

    SELECT TOP 1 @MeetingId=m.MeetingId FROM @Meeting AS m;
    SELECT TOP 1 @MeetingLocationId = ml.MeetingLocationId FROM @MeetingLocation AS ml;
    SELECT TOP 1 @AreaId = a.AreaId FROM  @Area AS a;

    UPDATE Areas SET 
        Hotline=areaParam.Hotline,
        Name=areaParam.Name
    FROM Areas INNER JOIN @Area AS areaParam
    ON Areas.AreaId=areaParam.AreaId;
    IF(@@ROWCOUNT=0)
        BEGIN;
            INSERT INTO Areas
                (Hotline,Name)
            SELECT areaParam.Hotline,areaParam.Name FROM @Area AS areaParam;
            SET @AreaId=SCOPE_IDENTITY();
        END;
    UPDATE MeetingLocations SET
        Address1=ml.Address1,
        Address2=ml.Address2,
        Address3=ml.Address3,
        City=ml.City,
        [State]=ml.[State],
        Zip=ml.Zip,
        ClubName=ml.ClubName,
        ClubDescription=ml.ClubDescription,
        MapLink=ml.MapLink
    FROM MeetingLocations INNER JOIN @MeetingLocation AS ml
    ON MeetingLocations.MeetingLocationId=ml.MeetingLocationId;
    IF(@@ROWCOUNT=0)
        BEGIN;
            INSERT INTO MeetingLocations 
                (Address1,Address2,Address3,City,[State],Zip,ClubName,ClubDescription,MapLink)
            SELECT ml.Address1,ml.Address2,ml.Address3,ml.City,ml.[State],ml.Zip,ml.ClubName,ml.ClubDescription,ml.MapLink
            FROM @MeetingLocation AS ml;
            SET @MeetingLocationId=SCOPE_IDENTITY();
        END;
    UPDATE Meetings SET 
        AreaId = @AreaId,
        MeetingLocationId=@MeetingLocationId,
        Name = meetingParam.Name
    FROM Meetings INNER JOIN @Meeting AS meetingParam
    ON Meetings.MeetingId=meetingParam.MeetingId;
    IF(@@ROWCOUNT=0)
        BEGIN;
            INSERT INTO Meetings
                (MeetingLocationId,AreaId,Name)
            SELECT @MeetingLocationId,@AreaId,meetingParam.Name FROM @Meeting AS meetingParam;
            SET @MeetingId=SCOPE_IDENTITY();
        END;
    RETURN @MeetingId;
END

C# code:

...create tables...
var meetingLocationParam = new SqlParameter("@MeetingLocation", meetingLocationTable);
meetingLocationParam.SqlDbType = SqlDbType.Structured;
meetingLocationParam.TypeName = "MeetingLocationsTableType";
var meetingParam = new SqlParameter("@Meeting", meetingTable);
meetingParam.SqlDbType = SqlDbType.Structured;
meetingParam.TypeName = "MeetingsTableType";
var areaParam = new SqlParameter("@Area", areaTable);
areaParam.TypeName = "AreasTableType";
areaParam.SqlDbType = SqlDbType.Structured;
using (var connection = new SqlConnection(conn.ConnectionString))
using (var command = new SqlCommand())
{
    connection.Open();
    command.Connection = connection;
    command.CommandText = "EXEC dbo.InsertUpdateMeeting";
    command.Parameters.AddRange(new SqlParameter[]
    {meetingParam, areaParam, meetingLocationParam, new SqlParameter()
    {
        Value=0,
        Direction=ParameterDirection.ReturnValue,
        SqlDbType=SqlDbType.Int,
        ParameterName="@MeetingId"
    } });
    var otherRet = command.ExecuteNonQuery();

    //Assert.IsTrue(ret > 0);
}

Upvotes: 0

Views: 1810

Answers (4)

Zach
Zach

Reputation: 3207

I just noticed you didn't declare your @MeetingId parameter in your SP definition (you did in the body but I don't think that can be used).

ALTER PROCEDURE [dbo].[InsertUpdateMeeting] 
    -- Add the parameters for the stored procedure here
    @Meeting MeetingsTableType READONLY,
    @Area AreasTableType READONLY,
    @MeetingLocation MeetingLocationsTableType READONLY,
    @MeetingId <datatype> OUTPUT -- ADD THIS
AS

Then in your code you can grab it with this:

command.Parameters["@MeetingId"].Value

Upvotes: 0

Scott Hannen
Scott Hannen

Reputation: 29212

That output value won't get returned from ExecuteNonQuery. Try creating a reference to your return parameter like this:

var returnParameter = new SqlParameter[]
{meetingParam, areaParam, meetingLocationParam, new SqlParameter()
{
    Value=0,
    Direction=ParameterDirection.ReturnValue,
    SqlDbType=SqlDbType.Int,
    ParameterName="@MeetingId"
} }

command.Parameters.Add(returnParameter);

Then after executing,

var myReturnedValue = returnParameter.Value;

You could also change

RETURN @MeetingId;

to

SELECT @MeetingId;

and then use

var myReturnedValue = (int)command.ExecuteScalar();

Upvotes: 2

jegtugado
jegtugado

Reputation: 5141

There are multiple ways to get a return value from a stored procedure using ADO.NET.

My example are generic methods I've used before. You can pass an SQL command using a stored procedure or text.

  1. SqlAdapter

    /// <summary>
    /// Returns a DataSet given an Sql Command
    /// </summary>
    /// <param name="cmd">The SqlCommand object</param>
    /// <returns>DataSet</returns>
    public static DataSet GetDataSet(SqlCommand cmd)
    {
        using (SqlConnection con = DbConnect()) // DbConnect() returns SqlConnection instance
        {
            DataSet ds = new DataSet();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            cmd.Connection = con;
            da.Fill(ds, "my_dataset");
    
            return ds;
        }
    }
    
  2. ExecuteScalar

    /// <summary>
    /// Returns a single value from the database given an Sql Command object
    /// </summary>
    /// <param name="cmd">The Sql Command object</param>
    /// <returns>string</returns>
    public static string GetSingleFromDatabase(SqlCommand cmd)
    {
        using (SqlConnection con = DbConnect()) // DbConnect() returns SqlConnection instance
        {
            cmd.Connection = con;
    
            try
            {
                object returnedValue = cmd.ExecuteScalar();
                if (returnedValue != null)
                {
                    return returnedValue.ToString();
                }
                else
                    return "";
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
    

Upvotes: 0

Sateesh Pagolu
Sateesh Pagolu

Reputation: 9606

You need to either use ExecuteScalar to catpure the returned value, or use the output parameter.

A simlar question was answered in this post. Calling stored procedure with return value

Upvotes: 0

Related Questions