如何通过 FromSqlRaw 在 EF Core 3.0 中调用存储过程

Posted

技术标签:

【中文标题】如何通过 FromSqlRaw 在 EF Core 3.0 中调用存储过程【英文标题】:How to call a stored procedure in EF Core 3.0 via FromSqlRaw 【发布时间】:2019-10-02 18:19:12 【问题描述】:

我最近从 EF Core 2.2 迁移到 EF Core 3.0。

不幸的是,我还没有找到一种方法来调用返回实体的存储过程。

在 EF Core 2.0 中是可能的:

var spParams = new object[]  "bla", "xx" ;
var createdPath = ModelContext.Paths.FromSql("AddNodeWithPathProc  @p0, @p1", spParams).Single();

在 EF Core 3.0 中,方法 FromSQL 被替换为 FromSqlRaw。但是,我没有设法成功调用存储过程然后处理该值。这在存储过程将数据插入数据库时​​很有用。

所以在 EF Core 3.0 中,我使用以下代码:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0, @p1", spParams).Single();

但它会抛出异常,因为生成的 SQL 是无效的,看起来像这样:

exec sp_executesql N'SELECT TOP(2) [p].[PathId], [p].[Level], [p].[NodeId], [p].[NodePath], [p].[NodePathString]
FROM (
     @sql @p0, @p1
) AS [p]',N'@p0 nvarchar(4000),@p1 nvarchar(4000), @sql nvarchar(100)',@p0=N'1a',@p1=N'', @sql=N'AddNodeWithPathProc'

我尝试了很多变体,但都没有成功。

我开始认为不可能使用ModelContext.[IQueryable].FromSqlRaw 运行存储过程。在我看来,这种方法打败了FromSqlRaw 的主要原因之一,因为对于普通的选择语句,LINQ 通常足够好。

有谁知道如何在 EF Core 3.0 中结合使用存储过程和 FromSqlRaw?非常感谢任何帮助。

提前致谢

PS:我知道您可以使用this.Database.ExecuteSqlRaw(SQL, parameters) 执行存储过程。但是,这样就无法检索存储过程查询的任何实体。

【问题讨论】:

尝试 .ToList() 而不是 .Single()。 .Single() 正在生成“TOP(2)”包装器。 我暂时的解决方法如下:this.ModelContext.ExecuteRawSql("EXEC AddNodeWithPathProc @p0, @p1", spParams); var createdPath = ModelContext.Paths.FromSqlRaw("SELECT TOP 1 * FROM dbo.Path ORDER BY PathID DESC").Single();但是,这不是一个可接受的生产解决方案。 是的.. ToList() 有效.. 非常感谢 :-) 【参考方案1】:

解决方案(感谢 David Browne,您应该将其发布为答案):

用 ToList 替换 Single 可以:-)

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc  0, 1", nodeTitle, parentPathString).ToList();

【讨论】:

【参考方案2】:

这非常奇怪……就在几天前,我遇到了同样的问题并关注了这篇文章。我接到了这个电话:

 public IEnumerable<TableChange> GetTableLastChanges(string tableName, string keyColumn, out int synchronizationVersion)
    
        var parameters = new[] 
            new SqlParameter("@table_name", SqlDbType.VarChar)  Direction = ParameterDirection.Input, Value = tableName ,
            new SqlParameter("@key_column", SqlDbType.VarChar)  Direction = ParameterDirection.Input, Value = keyColumn ,
            new SqlParameter("@synchronization_version", SqlDbType.BigInt)  Direction = ParameterDirection.InputOutput, Value = 0 
        ;

        var changes = this.TableChanges.FromSqlRaw("[dbo].[GetTableLastChanges] @table_name, @key_column, @synchronization_version OUTPUT", parameters).ToList();

        synchronizationVersion = Convert.ToInt32(parameters[2].Value);

        return changes;
    

现在一切正常,此调用按预期工作。因此,我应该承认 Core 3 上 EF 的数据集和参数返回没有问题。

【讨论】:

【参考方案3】:
var result=context.yourmodelclass.FromSqlInterpolated($"StoredProcedureName param1,param2").tolist();

如果需要,您可以添加多个参数。 注意:

context => 您的数据库名称。 yourmodelclass=> 您创建的模型文件夹中的类,用于从存储过程结果中获取输出结果。

【讨论】:

【参考方案4】:

我不在我可以测试的地方,但我认为以下方法会起作用:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc 0, 1", parm1 parm2).Single();

【讨论】:

不,这不起作用。刚刚测试过了。无效的 sql :-(。我相信它与生成的 sql 有关。如果我用探查器检查 sql,它总是遵循模式:sp_executesql 'SELECT * FROM mysqlPassedInMethod。我不会知道如何在此代码中传递存储过程.因此.net方法检测到传递的sql字符串用于存储过程并相应地调整生成的sql,或者在T-SQL中有一种我不知道的方法知道(我不是专家)【参考方案5】:

尝试分离SqlParameter:

SqlParameter param1 = new SqlParameter("@p0","value");
SqlParameter param2 = new SqlParameter("@p1","value");

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0 @p1", param1, 
param2).Single();

【讨论】:

在下方为您删除的帖子发布了解决方案。 刚试了一下,失败了:-(。错误是:“System.InvalidCastException: 'SqlParameterCollection 只接受非空SqlParameter 类型对象,不接受SqlParameter 对象。'”。没有sql发送到 sql server(根据 sql profiler) @jdweng 非常感谢 :) 当我登录到我的软件并下载最后更新的 XML 文件时,我有这个解决方案,但我需要所有历史数据而不会丢失。所以我有另一种选择来设置日期并下载带有费率的 excel 文件,但我不知道如何实现。在服务器上运行服务?也许用户一周不使用软件,所以我错过了整整一周的汇率。 @ISTech :查看以下页面:boi.org.il/en/Markets/Pages/explainxml.aspx 您可以在 url 中添加日期。 boi.org.il/currency.xml?rdate=20120101 @ISTech :我更新了下面的代码来做一个日期范围。【参考方案6】:

看看这里:

https://github.com/DarioN1/SPToCore

这是一个存储过程的脚手架,它可以帮助你使用sp。

它不是第三方库,它生成纯 c# 代码以包含在您的项目中,扩展当前 dbContext 以提供存储过程方法、参数映射和分类结果。

【讨论】:

以上是关于如何通过 FromSqlRaw 在 EF Core 3.0 中调用存储过程的主要内容,如果未能解决你的问题,请参考以下文章

包含在FromSqlRaw和EF Core 3.1中的存储过程中

如何比较 EF Core 插值查询中的整数列表

EF Core,禁用外键列名生成

在 EF Core 5.0 中使用 FromRawSql 会引发异常

如何使用 FromSqlRaw Entity Framework Core 3.1 从存储过程中返回多个 SELECT 集

使用 EF 生成的 MySQL 在 LinQ 中为 FromSqlRaw 在从系统中选择变量时返回“SQL 语法错误”