使用存储过程但没有 return table 数据在 EF Core 中获取输出参数值
Get output parameter value in EF Core with stored procedure but without return table data
我有一个存储过程,应该 return 通过 id:
登录
CREATE PROCEDURE MyProcedure
(
@id INT,
@login NVARCHAR(50) OUTPUT
)
AS
BEGIN
SELECT
ID
,
Login
FROM
Users
WHERE
ID = @id
END
GO
端点中的这段代码工作正常:
var id = new SqlParameter
{
ParameterName = "id",
SqlDbType = SqlDbType.Int,
Value = 15,
};
var login = new SqlParameter
{
ParameterName = "login",
SqlDbType = SqlDbType.NVarChar,
Direction = ParameterDirection.Output,
Size = 50,
};
var query = $"EXEC MyProcedure @{id}, @{login} OUTPUT";
var result = _context.Set<User>()
.FromSqlRaw(query, id, login).ToList();
foreach (var item in result) Console.WriteLine(item.Login);
和class:
public class User
{
public string Login { get; set; }
}
和属性:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasNoKey();
}
我得到一个包含一个搜索元素的列表,它的 Login
属性 就是我想要的。
但是如果我把SELECT
改成(原来的程序是这样的,我改不了):
SELECT
@id =
ID
,
@login =
Login
我收到错误消息The required column 'Login' was not present in the results of a 'FromSql' operation.
那么获得 Login
的正确方法是什么?
解决此问题的一个简单方法是使用 context.Database.ExecuteSqlInterpolated()
或 context.Database.ExecuteSqlRaw()
而不是 context.Set<T>().FromSqlRaw()
:
这是一个完整的示例控制台程序,演示了该方法:
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class User
{
public int UserId { get; set; }
public string Login { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63991939")
.UseLoggerFactory(LoggerFactory.Create(b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasData(
new User {UserId = 1, Login = "John"},
new User {UserId = 2, Login = "Jane"});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var connection = context.Database.GetDbConnection();
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"CREATE PROCEDURE uspGetUsers (
@userCount INT OUTPUT
) AS
BEGIN
SELECT
UserId,
Login
FROM
Users;
SELECT @userCount = @@ROWCOUNT;
END;";
command.ExecuteNonQuery();
}
var userCountParameter = new SqlParameter("@myUserCountParam", SqlDbType.Int) {Direction = ParameterDirection.Output};
context.Database.ExecuteSqlInterpolated($"EXEC uspGetUsers @userCount={userCountParameter} OUTPUT");
Debug.Assert((int)userCountParameter.Value == 2);
}
}
}
您可以 运行 使用此 .NET Fiddle 的示例代码。
我有一个存储过程,应该 return 通过 id:
登录CREATE PROCEDURE MyProcedure
(
@id INT,
@login NVARCHAR(50) OUTPUT
)
AS
BEGIN
SELECT
ID
,
Login
FROM
Users
WHERE
ID = @id
END
GO
端点中的这段代码工作正常:
var id = new SqlParameter
{
ParameterName = "id",
SqlDbType = SqlDbType.Int,
Value = 15,
};
var login = new SqlParameter
{
ParameterName = "login",
SqlDbType = SqlDbType.NVarChar,
Direction = ParameterDirection.Output,
Size = 50,
};
var query = $"EXEC MyProcedure @{id}, @{login} OUTPUT";
var result = _context.Set<User>()
.FromSqlRaw(query, id, login).ToList();
foreach (var item in result) Console.WriteLine(item.Login);
和class:
public class User
{
public string Login { get; set; }
}
和属性:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasNoKey();
}
我得到一个包含一个搜索元素的列表,它的 Login
属性 就是我想要的。
但是如果我把SELECT
改成(原来的程序是这样的,我改不了):
SELECT
@id =
ID
,
@login =
Login
我收到错误消息The required column 'Login' was not present in the results of a 'FromSql' operation.
那么获得 Login
的正确方法是什么?
解决此问题的一个简单方法是使用 context.Database.ExecuteSqlInterpolated()
或 context.Database.ExecuteSqlRaw()
而不是 context.Set<T>().FromSqlRaw()
:
这是一个完整的示例控制台程序,演示了该方法:
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class User
{
public int UserId { get; set; }
public string Login { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63991939")
.UseLoggerFactory(LoggerFactory.Create(b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasData(
new User {UserId = 1, Login = "John"},
new User {UserId = 2, Login = "Jane"});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var connection = context.Database.GetDbConnection();
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"CREATE PROCEDURE uspGetUsers (
@userCount INT OUTPUT
) AS
BEGIN
SELECT
UserId,
Login
FROM
Users;
SELECT @userCount = @@ROWCOUNT;
END;";
command.ExecuteNonQuery();
}
var userCountParameter = new SqlParameter("@myUserCountParam", SqlDbType.Int) {Direction = ParameterDirection.Output};
context.Database.ExecuteSqlInterpolated($"EXEC uspGetUsers @userCount={userCountParameter} OUTPUT");
Debug.Assert((int)userCountParameter.Value == 2);
}
}
}
您可以 运行 使用此 .NET Fiddle 的示例代码。