如何通过 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 5.0 中使用 FromRawSql 会引发异常
如何使用 FromSqlRaw Entity Framework Core 3.1 从存储过程中返回多个 SELECT 集