简体   繁体   中英

Why does Dapper QueryAsync<T> behave differently from Query<T> with sproc return values?

I have a stored procedure that performs a check, and returns either a row or a non-zero return value:

CREATE PROCEDURE dbo.ConditionalGet
    @ID INT
AS
BEGIN

    -- this is a silly made up condition just to test the issue
    IF @ID % 2 = 1
    BEGIN
        RETURN -1
    END

    SELECT *
    FROM MyTable
    WHERE ID = @ID

    RETURN 0
END

And I have a C# repo class that uses Dapper to return the result or throw an exception:

public class Repo
{
    public MyClass Get(int id)
    {
        using (var conn = GetSqlConnection())
        {
            var p = new { ID = id };
            var pWithReturnValue = new DynamicParameters(p);
            p.Add("return", null, DbType.Int32, ParameterDirection.ReturnValue);

            var result = conn.Query<MyClass>("dbo.ConditionalGet", p, commandType: CommandType.StoredProcedure);

            var errorCode = p.Get<int>("return");
            if (errorCode != 0)
                throw new RepositoryGetException(errorCode);

            return result.FirstOrDefault();
        }
    }
}

And this works as expected: when id is divisible by 2, the hydrated object is returned, otherwise an exception is thrown.

HOWEVER, this fails when I make the code Async!

public class Repo
{
    public async Task<MyClass> Get(int id)
    {
        using (var conn = GetSqlConnection())
        {
            var p = new { ID = id };
            var pWithReturnValue = new DynamicParameters(p);
            p.Add("return", null, DbType.Int32, ParameterDirection.ReturnValue);
            // this is the only change!
            var result = await conn.QueryAsync<MyClass>("dbo.ConditionalGet", p, commandType: CommandType.StoredProcedure);

            var errorCode = p.Get<int>("return");
            if (errorCode != 0)
                throw new RepositoryGetException(errorCode);

            return result.FirstOrDefault();
        }
    }
}

This throws an InvalidOperationException "No columns were selected"!

I really like the pattern here and would like to use it asynchronously, so why the failure? I've tried turning buffering off and on and it didn't make a difference.

Currently Dapper doesn't support for Async methods that no perform a SELECT statement.
There is a open issue about that in Github:
https://github.com/StackExchange/Dapper/issues/591

What you do for now is something like:

ALTER PROCEDURE dbo.ConditionalGet
    @ID INT,
    @Output INT OUTPUT
AS
BEGIN

    -- this is a silly made up condition just to test the issue
    IF @ID % 2 = 1
    BEGIN
        SET @Output = -1
    END
    ELSE BEGIN
        SET @Output = 0
    END

    SELECT *
    FROM MyTable
    WHERE ID = @ID
END

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM