精巧的区分返回值和结果集

时间:2018-04-24 14:29:59

标签: dapper

我正在使用Dapper' QueryMultipleAsync方法来读取多个结果集。我的存储过程检查某些条件(例如,用户可能通过向我的API发送Id来尝试获取其他人的数据)以确定数据是否应该返回。

我,在C#方面,首先需要读取return value(不是结果集)来确定是否返回数据或者只返回SP 3(这意味着权利不足)。为了说明这个案例:

IF @UserRole < 10
BEGIN
    RETURN 3; -- Insufficient rights.
END

IF @IsCurrentUserOwner = 0
BEGIN
    RETURN 5; -- Not owner.
END

-- Get users.
SELECT
        Id
    ,   [Name]
    ,   LastName
FROM
    Users
-- WHERE  ...

-- Get chat messages.
SELECT
    *
FROM
    ChatMessages
-- WHERE  ...

我知道outputreturn值写在读者的末尾,因此我只能在读取所有数据(结果集)时读取返回参数。所以,我总是先读取结果集然后返回/输出参数。

如果我的SP看起来像这样:

-- ...some code above...
IF @IsCurrentUserOwner = 0
BEGIN
    RETURN 5; -- Not owner.
END

DECLARE @RType TINYINT = NULL

-- some other code here to get @RType value here...

SELECT @RType -- To make this a result so QueryMultiple's reader can read this.

-- ...some other code to get users and chat messages...

描述问题:

@RType变量可以是5以及SP的返回值。当我首先读取结果时(因为输出/返回参数位于读者的末尾),我怎么知道我刚刚读取的值(在这种情况下是5)是@RType还是返回值? (他们是可兑换的)

这就是我的C#代码大致如下:

var parameters = new DynamicParameters();
parameters.Add("@RetVal", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
var dbResult = await Context.SqlConnection.QueryMultipleAsync(sql: "my_sp_name", param: parameters, commandType: CommandType.StoredProcedure)
// Some code here...

using (var reader = dbResult)
{
    var rType = reader.Read<byte>(); // <----- How to know if I read @RType or just return value of SP since they are convertible to each other?
    var users = reader.Read<User>();
    var chatMessages = reader.Read<ChatMessage>();
    // ...
}

var returnValue = parameters.Get<int>("@RetVal");
if (returnValue == 5)
{
    return "You are not allowed to see this data";
}

你怎么建议我处理这个案子?

2 个答案:

答案 0 :(得分:0)

您的C#代码使用async - await(QueryMultipleAsync),目前Dapper不支持不执行SELECT语句的Async方法。 在Github中存在一个未解决的问题: https://github.com/StackExchange/Dapper/issues/591

选项1
您可以将存储过程拆分为两部分:
1.检查返回值 2.获取选择陈述
选项2

ALTER PROCEDURE dbo.sp
    ... your params..
    @Output INT OUTPUT
AS
    IF @UserRole < 10
    BEGIN
        SET @Output = 3; -- Insufficient rights.
    END

    IF @IsCurrentUserOwner = 0
    BEGIN
        SET @Output = 5; -- Not owner.
    END

    -- Get users.
    SELECT
            Id
        ,   [Name]
        ,   LastName
    FROM
        Users
    -- WHERE  ...

    -- Get chat messages.
    SELECT
        *
    FROM
        ChatMessages
    -- WHERE  ...

选项3
使用ADO.NET

答案 1 :(得分:0)

我对你的问题并不是很清楚,但下面的代码段应该可行。由于您将@RetVal定义为ParameterDirection.ReturnValue,因此您应该能够在访问实际读者之前访问它。我能够在SQL SERVER中验证这是有效的。

var returnValue = parameters.Get<int>("@RetVal");
if (returnValue == 5 || returnValue == 3)
{
    return "You are not allowed to see this data";
}


using (var reader = dbResult)
{
    var rType = reader.Read<byte>(); // <----- How to know if I read @RType or just return value of SP since they are convertible to each other?
    var users = reader.Read<User>();
    var chatMessages = reader.Read<ChatMessage>();
    // ...
}

这是我的存储过程

ALTER PROCEDURE mysp_TestOne 
@p1 int 

AS
BEGIN
    SET NOCOUNT ON;


    if @p1 > 0
    return 5;


    SELECT 1 F1
    union 
    Select 2 F1;

    SELECT 1 F1
    union 
    Select 2 F1;

END
GO

更完整的c#片段;

using (SqlConnection cn = new SqlConnection(connectionString))

{
    var sql = @"mysp_TestOne";
    var parameters = new DynamicParameters();

    // @p1 triggers whether to return query results or just the returnvalue
    parameters.Add("p1", 0, direction: ParameterDirection.Input);
    parameters.Add("@RetVal", 0, direction: ParameterDirection.ReturnValue);
    var dbResult = await cn.QueryMultipleAsync(sql, parameters, commandType: CommandType.StoredProcedure);

    var returnValue = parameters.Get<int>("@RetVal");
    if (returnValue == 5 || returnValue == 3)
    {
        return "You are not allowed to see this data";
    }


    using (var reader = dbResult)
    {
        var rType = reader.Read<byte>(); // <----- How to know if I read @RType or just return value of SP since they are convertible to each other?
        var users = reader.Read<User>();
        var chatMessages = reader.Read<ChatMessage>();
        // ...
    }

}

HTH