使用Dapper.net调用存储过程时,总是返回-1。

10

这是我的存储过程。测试时,总能得到正确的结果。

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

然而,当我使用dapper.net调用此存储过程时,总是返回-1。

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

很可能dapper.net无法获取存储过程的返回值。但我真的不知道如何修复它。请帮忙。

4个回答

22
因为你的存储过程有 SET NOCOUNT ON; 这个语句,它会 "在任何 DML 后抑制“xx 行受影响”消息",所以 Execute() 返回 -1。详见此问题。是否禁用此功能是另一个问题,也在该链接中讨论。
我遇到了相同的问题,所以想分享我的看法。

从未知道这个!+1 - nawfal
谢谢!我在创建一个基于SELECT的INSERT存储过程后,没有删除SET NOCOUNT ON;这一行代码,让我非常苦恼。 - DotNetDublin
感谢你的帮助,我已经搜索了20多分钟 :) - L. Mihai

15

找到解决方案了,这是我在网上找到的示例代码,并且它可以工作。

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"); 

2

最近我需要修改一个现有的过程,使其额外返回一个值,并且我一直在使用匿名类型来传递参数。在这种情况下,非常好的一点是 DynamicParameters 支持将匿名类型作为输入参数,这使得实现这个变化变得容易。

我原来的代码如下:

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

我能够将其更改为:
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");

2

看起来Dapper.net在Execute方法中使用SqlCommand.ExecuteNonQuery。它返回受影响的行数,而不是返回语句的值。你需要找的是Query方法。

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

虽然我认为这也无法捕获返回语句,因此您需要更改存储过程以返回结果集。

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

或者你可以使用另一种数据库访问方法。


谢谢您的回复。但是您仍然需要执行,我在网上找到了另一个示例,它可以正常工作。 - qinking126

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接