10

here's my stored procedure. when I test it, always get correct result back.

ALTER PROCEDURE [dbo].[AddSmoothieIngredients]
    -- Add the parameters for the stored procedure here
    @Query NVARCHAR(4000) ,
    @SmoothieId INT ,
    @CreatedDate DATETIME ,
    @Status INT ,
    @UserId INT
AS 
    BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
        SET NOCOUNT ON;

        BEGIN TRY
            BEGIN TRAN

            IF @SmoothieId > 0 
                BEGIN
                    DELETE  FROM dbo.SmoothieIngredients
                    WHERE   SmoothieId = @SmoothieId;

                    EXECUTE (@Query);
                END
            ELSE 
                BEGIN

                    IF @UserId = 0 
                        SET @UserId = NULL;

                    INSERT  INTO dbo.Smoothie
                            ( Name, CreatedDate, Status, UserId )
                    VALUES  ( N'', @CreatedDate, @Status, @UserId );

                    SET @SmoothieId = SCOPE_IDENTITY();

                    SET @Query = REPLACE(@Query, 'sId', @SmoothieId);
                    EXECUTE (@Query);

                END 


            COMMIT TRAN

            RETURN @SmoothieId

        END TRY

        BEGIN CATCH
            ROLLBACK
        END CATCH

    END

However When I call this stored procedure using dapper.net, always return -1 back.

        using (var conn = OpenConnection())
        {
            var parameter = new { Query = query, SmoothieId = smoothieId, CreatedDate = createdDate, Status = status, UserId = userId  };
            return conn.Execute("AddSmoothieIngredients", parameter, commandType: CommandType.StoredProcedure);
        }

Probably, dapper.net cannot pick up the return value from the stored procedure. but I really dont know how to fix it. please help.

qinking126
  • 11,385
  • 25
  • 74
  • 124

4 Answers4

22

So the reason that Execute() returns -1 is because your sproc has SET NOCOUNT ON; which "suppresses the "xx rows affected" message after any DML" according to this question. Whether you want to disable that or not is another question also discussed in that link.

I just came across the same problem so I thought I'd throw in my 2 cents.

Community
  • 1
  • 1
joakes
  • 221
  • 2
  • 7
15

Found the solution, here's the sample code I found online. and it works.

var p = new DynamicParameters();
p.Add("@a", 11);
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure); 

int b = p.Get<int>("@b");
int c = p.Get<int>("@c"); 
qinking126
  • 11,385
  • 25
  • 74
  • 124
2

It looks like Dapper.net uses the SqlCommand.ExecuteNonQuery for the Execute method. This returns the number of rows affected, not the value of the return statement. What you're looking for is Query

return connection.Query<int>("AddSmoothieIngredients", parameter, commandType: CommandType.StoredProcedure).First();

Although I don't think that will capture the return statement either, in which case you'll need to alter the stored procedure to return a results set.

ALTER PROCEDURE [dbo].[AddSmoothieIngredients]
    -- Add the parameters for the stored procedure here
    @Query NVARCHAR(4000) ,
    @SmoothieId INT ,
    @CreatedDate DATETIME ,
    @Status INT ,
    @UserId INT
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
    SET NOCOUNT ON;

    BEGIN TRY
        BEGIN TRAN

        IF @SmoothieId > 0 
            BEGIN
                DELETE  FROM dbo.SmoothieIngredients
                WHERE   SmoothieId = @SmoothieId;

                EXECUTE (@Query);
            END
        ELSE 
            BEGIN

                IF @UserId = 0 
                    SET @UserId = NULL;

                INSERT  INTO dbo.Smoothie
                        ( Name, CreatedDate, Status, UserId )
                VALUES  ( N'', @CreatedDate, @Status, @UserId );

                SET @SmoothieId = SCOPE_IDENTITY();

                SET @Query = REPLACE(@Query, 'sId', @SmoothieId);
                EXECUTE (@Query);

            END 


        COMMIT TRAN

        SELECT @SmoothieId
        RETURN
    END TRY

    BEGIN CATCH
        ROLLBACK
    END CATCH

END

Or you could use another DB access method.

Zeph
  • 1,728
  • 15
  • 29
2

Recently I had to change an existing procedure to additionally return a value, and I had been using an anonymous type to pass the parameters. In this context, the really nice thing is that DynamicParameters supports an anonymous type as an input parameter, which makes this change easy to implement.

I had the following:

cnn.Execute("spMagicProc", new { a = 11, x = 13, y = 14, z = "something" },
  commandType: commandType.StoredProcedure);

I was able change that to:

var p = new DynamicParameters(new { a = 11, x = 13, y = 14, z = "something" });
p.Add("@rval", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure);

int rval = p.Get<int>("@rval");
takrl
  • 6,356
  • 3
  • 60
  • 69