使用 EF Core 和 ExecuteSqlCommandAsync 从存储过程中的 SELECT 语句访问结果
Access result from SELECT statement in stored procedure using EF Core and ExecuteSqlCommandAsync
我正在尝试使用 EF Core 中的 ExecuteSqlCommandAsync
在具有空 RETURN
语句的有点奇怪的遗留存储过程中获取 select 查询的结果。
存储过程如下所示:
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
语句为空)。但是,有什么方法可以使用 EF Core 从 NextValue
获取值吗?似乎 FromSql
可能有效,但我真的只对取回单个值感兴趣,而不是实体。 This answer 似乎可以满足我的要求,但如果可能的话,我宁愿使用 EF Core 而不是 SqlCommand
。
您可以执行如下操作。我只在 SQL 中将我的示例写到 运行,但 c# 部分的概念应该相同。如果您打算将其扩展,我建议您使用 SqlCommand。 Return 也只有 every 适用于整数。
因为你可以 return 任何整数值,你可以只说 Return [整数]
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
必须是FromSql
。在 EF Core 2.0 中不可能。在 EF Core 2.1 中可能,但比需要的要复杂一些,因为 SQL 返回原始类型的查询仍然不受支持。所以你需要像这样使用 Query Type:
首先您需要创建一个 "query type" class 来保存结果:
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();
您还应该将查询更改为使用 UPDATE … OUTPUT,这样两个会话就不会获得相同的值。 EG
CREATE PROCEDURE [dbo].[SelectNextCounter]
(
@CounterName nvarchar(50)
)
AS
UPDATE counter
SET NextValue = NextValue + 1
OUTPUT INSERTED.NextValue
WHERE CounterName = @CounterName
GO
我正在尝试使用 EF Core 中的 ExecuteSqlCommandAsync
在具有空 RETURN
语句的有点奇怪的遗留存储过程中获取 select 查询的结果。
存储过程如下所示:
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
语句为空)。但是,有什么方法可以使用 EF Core 从 NextValue
获取值吗?似乎 FromSql
可能有效,但我真的只对取回单个值感兴趣,而不是实体。 This answer 似乎可以满足我的要求,但如果可能的话,我宁愿使用 EF Core 而不是 SqlCommand
。
您可以执行如下操作。我只在 SQL 中将我的示例写到 运行,但 c# 部分的概念应该相同。如果您打算将其扩展,我建议您使用 SqlCommand。 Return 也只有 every 适用于整数。
因为你可以 return 任何整数值,你可以只说 Return [整数] 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
必须是FromSql
。在 EF Core 2.0 中不可能。在 EF Core 2.1 中可能,但比需要的要复杂一些,因为 SQL 返回原始类型的查询仍然不受支持。所以你需要像这样使用 Query Type:
首先您需要创建一个 "query type" class 来保存结果:
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();
您还应该将查询更改为使用 UPDATE … OUTPUT,这样两个会话就不会获得相同的值。 EG
CREATE PROCEDURE [dbo].[SelectNextCounter]
(
@CounterName nvarchar(50)
)
AS
UPDATE counter
SET NextValue = NextValue + 1
OUTPUT INSERTED.NextValue
WHERE CounterName = @CounterName
GO