Доступ к результату из инструкции SELECT в хранимой процедуре с использованием EF Core и ExecuteSqlCommandAsync - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь использовать ExecuteSqlCommandAsync из EF Core, чтобы получить результат запроса select в несколько странной устаревшей хранимой процедуре с пустым оператором RETURN.

Хранимая процедура выглядит следующим образомthis:

CREATE PROCEDURE [dbo].[SelectNextCounter]
(
@CounterName nvarchar(50)
)
AS
    UPDATE  counter
    SET NextValue = NextValue + 1
    WHERE   CounterName = @CounterName
    SELECT  NextValue
    FROM    counter
    WHERE   counterName = @CounterName
RETURN
GO

Используя этот код, я могу получить доступ к значению RETURN хранимой процедуры (хотя меня действительно интересует NextValue):

var counterName = new SqlParameter
{
    ParameterName = "@CounterName",
    Value = "CustomerNumber",
    SqlDbType = SqlDbType.NVarChar
};
var returnValue = new SqlParameter
{
    ParameterName = "@return_value",
    Direction = ParameterDirection.Output,
    SqlDbType = SqlDbType.Int
};

await _context
    .Database
    .ExecuteSqlCommandAsync(
        "EXEC @return_value = SelectNextCounter @CounterName", counterName, returnValue
    );

Затем я могу получить значение через returnValue.Value (который всегда равен 0 из-за пустого оператора RETURN).Однако есть ли способ получить значение из NextValue с помощью EF Core?Похоже, что FromSql может работать, но я на самом деле просто заинтересован в получении единственного значения, а не сущности. Этот ответ , кажется, делает то, что я хочу, но я бы предпочел использовать EF Core, чем SqlCommand, если это возможно.

Ответы [ 3 ]

0 голосов
/ 13 октября 2018

Должно быть FromSql.Не возможно в EF Core 2.0.Возможно в EF Core 2.1, но немного сложнее, чем нужно, потому что SQL-запросы, возвращающие примитивные типы, все еще не поддерживаются.Поэтому вам нужно использовать Тип запроса следующим образом:

Сначала вам нужно создать класс «типа запроса», который будет содержать результат:

public class SelectNextCounterResult
{
    public int NextValue { get; set; }
}

Второй вынеобходимо зарегистрировать его в OnModelCreating переопределении:

modelBuilder.Query<SelectNextCounterResult>();

Затем вы можете использовать его для вызова вашего SP

var counterName = "CustomerNumber";
var result = await context.Query<SelectNextCounterResult>()
    .FromSql($"SelectNextCounter {counterName}")
    .FirstAsync();
0 голосов
/ 13 октября 2018

Также вы должны изменить запрос на использование UPDATE… OUTPUT, чтобы два сеанса не получали одно и то же значение.EG

CREATE PROCEDURE [dbo].[SelectNextCounter]
(
@CounterName nvarchar(50)
)
AS

    UPDATE  counter
    SET NextValue = NextValue + 1
    OUTPUT INSERTED.NextValue
    WHERE   CounterName = @CounterName

GO
0 голосов
/ 12 октября 2018

Вы можете сделать что-то вроде следующего.Я написал свой пример для запуска только на SQL, но концепция должна быть такой же для части c #.Я бы порекомендовал использовать SqlCommand, если вы когда-нибудь захотите, чтобы это было расширяемым.Возврат также только для каждой работы с целыми числами.

Поскольку вы можете вернуть любое целочисленное значение, вы можете просто сказать: Return [integer] https://docs.microsoft.com/en-us/sql/t-sql/language-elements/return-transact-sql?view=sql-server-2017

CREATE PROCEDURE [dbo].TestProc
AS
DECLARE @returnVal INT = (SELECT 2)
RETURN @returnVal
GO

DECLARE @newReturnVal INT
EXEC @newReturnVal = [dbo].TestProc
SELECT @newReturnVal
...