【问题标题】:How to run a stored procedure in EF Core 3.14如何在 EF Core 3.14 中运行存储过程
【发布时间】:2020-05-21 12:31:12
【问题描述】:

我正在研究完全使用 .NET Core 构建的新平台的安全性和用户管理。

特别是我正在尝试为新用户生成一个随机密码。我已将大量英语单词加载到表中,并创建了一个存储过程以从表中选择随机单词并以正确的马电池主食格式编写密码。

存储过程 (Passwords.GenerateRandomPassword) 不接受任何参数并返回名为 password 的单行 varchar 列。

到目前为止一切正常。我可以直接对服务器运行查询,它工作正常。

我的 userRepository 上有一个方法,如下所示:

public async Task<string> GenerateRandomPassword()
{

}

但我不知道如何让 EF Core 3.14 调用此存储过程并返回一个值。

文档可能不是最新的,或者我可能缺少程序集参考。

context 对象和 context.database 对象似乎不包含任何看起来允许我执行存储过程和检索值的方法。

文档似乎表明应该有 FromSQL 方法或类似方法。

任何帮助将不胜感激。

【问题讨论】:

  • 使用 SQL 客户端类运行存储过程。见mssqltips.com/sqlservertip/5810/…
  • @jdweng 我通常会使用 sqlclient。我在应用程序的其他任何地方都使用它,因为我更喜欢使用 sprocs 并因此使用我自己的 SQL 而不是生成的 SQL 来查询数据库。我在与应用程序数据不同的数据库中有用户帐户,因为它实际上只有三个表,用户、角色和用户角色,我认为这是我尝试 EF 的好机会,因为我没有使用它年。

标签: c# sql-server entity-framework-core


【解决方案1】:

一般的解决方案是调用db.Database.GetDbConnection(),它给你ADO.NET连接对象,你可以直接使用。

例如

var con = (SqlConnection)db.Database.GetDbConnection();
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "exec ...";

还有db.Database.ExecuteSqlxxx 方法,适用于简单的情况。

【讨论】:

  • 谢谢大卫 - 问题是我的 _context.Database 对象上没有 ExecuteSQL 方法。
  • 这是一个扩展方法,所以你需要一个using 来查看它的命名空间,例如using Microsoft.EntityFrameworkCore;
  • Microsoft.EntityFrameworkCore 已包含在内。也许扩展方法已经移动?
【解决方案2】:

你想看的是keyless entity types

这是 EF Core 3.0 中的 new feature

一个usage是从原始sql查询中检索数据。

使用 PostgreSQL

在 PostgreSQL 中,我们创建了一个函数来生成密码:

CREATE OR REPLACE FUNCTION generate_password() RETURNS text AS $$
  BEGIN
    RETURN (SELECT substring(md5(random()::text) from 0 for 12));
  END
$$ LANGUAGE plpgsql;

我们创建我们的实体:

public class PasswordGenerator
{
    public string Password { get; set; }
}

在我们应用程序的 DbContext 中,我们 configure 我们的实体:

public DbSet<PasswordGenerator> PasswordGenerator { get; set; }

public MyDbContext(DbContextOptions options) 
    : base(options)
{}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PasswordGenerator>().HasNoKey();
}

我们使用FromSqlRaw 方法调用返回密码的函数:

public async Task<string> GetGeneratedPassword()
{
    var pg = await _context.PasswordGenerator
        .FromSqlRaw(@"SELECT * from generate_password() AS ""Password""")
        .FirstAsync();

    return pg.Password;
}

我们使用别名“密码”将我们的查询正确映射到我们的实体。

安装的两个包是:Microsoft.EntityFrameworkCoreNpgsql.EntityFrameworkCore.PostgreSQL

使用 SQL Server

我们创建一个存储过程来生成密码:

CREATE OR ALTER PROCEDURE generate_password
AS
    SET NOCOUNT ON
    SELECT SUBSTRING (CONVERT(varchar(255), NEWID()), 0, 12) AS "Password"
    RETURN  
GO

使用别名“密码”将我们的查询正确映射到我们的实体。

下面是我们如何使用FromSqlRaw 方法:

public async Task<string> GetGeneratedPassword()
{
    var pg = (await _context.PasswordGenerator
        .FromSqlRaw("EXEC generate_password")
        .ToListAsync())
        .First();

    return pg.Password;
}

LINQ 查询期望我们的原始查询是 composable,这就是我们在 FromSqlRaw 方法之后立即调用 ToListAsync() 的原因。

SQL Server 不允许组合存储过程调用,因此任何 尝试将其他查询运算符应用于此类调用将导致 在无效的 SQL 中。正确使用AsEnumerableAsAsyncEnumerable 方法 在FromSqlRawFromSqlInterpolated 方法之后确保EF Core 不会尝试对存储过程进行组合。

安装的两个包是:Microsoft.EntityFrameworkCoreMicrosoft.EntityFrameworkCore.SqlServer

更新 - 使用GetDbConnection 方法

感谢@David Browne - Microsoft 提供的answer,我们可以调用GetDbConnection 扩展方法直接访问数据库。

public async Task<string> GetGeneratedPassword()
{
    var password = "";
    var connection = _context.Database.GetDbConnection();
    try
    {
        await connection.OpenAsync();
        using (var command = connection.CreateCommand())
        {
            // SQL Server
            command.CommandText = "EXEC generate_password";

            // PostgreSQL
            // command.CommandText = @"SELECT * from generate_password()";
            using (var reader = await command.ExecuteReaderAsync())
            {
                if (await reader.ReadAsync())
                {
                    password = reader.GetString(0);
                }
            }
        }
    }
    finally
    {
        await connection.CloseAsync();
    }

    return password;
}

【讨论】:

    猜你喜欢
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 2023-03-21
    相关资源
    最近更新 更多