Отличительное возвращаемое значение и набор результатов - PullRequest
0 голосов
/ 24 апреля 2018

Я использую метод Dapper QueryMultipleAsync для чтения множества результатов.Моя хранимая процедура проверяет некоторые условия (например, пользователь может пытаться получить чужие данные, отправив идентификатор в мой API), чтобы определить, должны ли данные возвращаться или нет.

I, на стороне 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  ...

Я знаю, что значения output и return записываются в конце считывателя, поэтому я могу прочитать возвращаемый параметр, только когда все данные (набор результатов) прочитаны.Поэтому мне всегда нужно сначала прочитать набор результатов, а затем вернуть / вывести параметры.

Что если бы мой 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 голосов
/ 24 апреля 2018

Я не совсем понял ваш вопрос, но приведенный ниже фрагмент должен работать. Поскольку вы определяете @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>();
        // ...
    }

}

НТН

0 голосов
/ 24 апреля 2018

Ваш код на C # использует async - await (QueryMultipleAsync), и в настоящее время Dapper не поддерживает методы Async, которые не выполняют оператор SELECT.В Github есть открытый вопрос: https://github.com/StackExchange/Dapper/issues/591

Опция 1 Вы можете разделить вашу хранимую процедуру на 2 части: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

...