【问题标题】:Are EF Core 3.1 ExecuteSqlRaw / ExecuteSqlRawAsync drop-in replacements for ExecuteSqlCommand / ExecuteSqlCommandAsync?EF Core 3.1 ExecuteSqlRaw / ExecuteSqlRawAsync 是 ExecuteSqlCommand / ExecuteSqlCommandAsync 的替代品吗?
【发布时间】:2020-04-26 23:34:00
【问题描述】:

升级到 EFCore 3.1 后出现弃用警告:

警告 CS0618 'RelationalDatabaseFacadeExtensions.ExecuteSqlCommandAsync(DatabaseFacade, RawSqlString, params object[])' 已过时:'对于使用纯字符串异步执行 SQL 查询,请改用 ExecuteSqlRawAsync。对于使用插值字符串语法创建参数的 SQL 查询的异步执行,请改用 ExecuteSqlInterpolatedAsync。'

警告 CS0618 'RelationalDatabaseFacadeExtensions.ExecuteSqlCommand(DatabaseFacade, RawSqlString, params object[])' 已过时:'对于使用纯字符串执行 SQL 查询,请改用 ExecuteSqlRaw。对于使用插值字符串语法创建参数的 SQL 查询执行,请改用 ExecuteSqlInterpolated。'

它们相关的旧代码如下所示:

context.Database.ExecuteSqlCommand("DELETE FROM Table WHERE ID = @p0", id);
await context.Database.ExecuteSqlCommandAsync("DELETE FROM Table2 WHERE ID = @p0", id);

咨询the fine manual,根本没有讨论典型的SQL Server参数@somename,事实上我什至看不到文档中的示例代码,它们显示在表名后打开括号,是有效的 SQL 语法:

context.Database.ExecuteSqlRaw("SELECT * FROM [dbo].[SearchBlogs]({0})", userSuppliedSearchTerm)

我没有看到文档在哪里定义了 userSuppliedSearchTerm 变量的内容或其类型,我正在努力看看它是如何明智地成为 SQL 的块(string userSuppliedSearchTerm = "WHERE id = 123"; 带有烘焙值? SQL 注入?)或单个原始值(int userSuppliedSearchTerm = 123),这是否意味着它是某种自定义类型,它指定了 db 列名和值? EFCore 如何知道要查询表中的哪一列? EFCore 是否会整理出括号中出现的语法错误? EFCore 必须使用括号来理解查询吗?

最终我的问题是:鉴于我的 ExecuteSqlCommand 代码有意义,而 ExecuteSqlRaw 的文档没有什么意义/似乎解释得不好,我们如何从这个工作代码出发:

var id = 123;
context.Database.ExecuteSqlCommand("DELETE FROM Table WHERE ID = @p0", id);

要使用 ExecuteSqlRaw?

SomeType x = ???;
context.Database.ExecuteSqlRaw("???", x);

【问题讨论】:

    标签: c# entity-framework-core ef-core-3.1


    【解决方案1】:

    规则很简单。

    EF Core 2.x 有 3 个ExecuteSqlCommand 重载:

    public static int ExecuteSqlCommand(this DatabaseFacade databaseFacade,
        RawSqlString sql, params object[] parameters); // 1
    public static int ExecuteSqlCommand(this DatabaseFacade databaseFacade,
       RawSqlString sql, IEnumerable<object> parameters); // 2
    public static int ExecuteSqlCommand(this DatabaseFacade databaseFacade,
        FormattableString sql); // 3
    

    在 EF Core 3.x 中映射到哪个

    public static int ExecuteSqlRaw(this DatabaseFacade databaseFacade,
        string sql, params object[] parameters); // 1
    public static int ExecuteSqlRaw(this DatabaseFacade databaseFacade,
        string sql, IEnumerable<object> parameters); // 2
    public static int ExecuteSqlInterpolated(this DatabaseFacade databaseFacade,
        FormattableString sql); // 3
    

    在功能上它们是完全等价的。 Raw 重载支持与 v2.x 重载 #1 和 #2 相同的占位符和参数值(命名和未命名)。 Interpolated 的行为与 v2.x 重载 #3 完全相同。

    重命名方法并为内插和非内插sql 参数使用不同名称的原因是v2.x 重载#1 和#3 的C# 编译时重载解决方案。有时,当意图使用另一个时,它会选择插值,反之亦然。使用不同的名称可以明确意图。

    您可以在 EF Core 3.0 Breaking Changes - FromSql, ExecuteSql, and ExecuteSqlAsync have been renamed 中阅读有关推理的更多信息。

    支持的参数占位符、名称和值的信息可以在Raw SQL queries - Passing parameters中找到。

    但要回答你的具体问题,如果现有的 v2.x 代码是

    context.Database.ExecuteSqlCommand("DELETE FROM Table WHERE ID = @p0", id);
    

    然后将其更改为ExecuteSqlRaw

    如果是的话

    context.Database.ExecuteSqlCommand($"DELETE FROM Table WHERE ID = {id}");
    

    然后将其更改为ExecuteSqlInterpolated

    【讨论】:

      【解决方案2】:

      我没有看到文档在哪里定义了 userSuppliedSearchTerm 变量的内容或其类型,我正在努力了解它是如何合理地成为 SQL 的块(字符串 userSuppliedSearchTerm = "WHERE id = 123";带有烘焙值?SQL 注入?)或单个原始值(int userSuppliedSearchTerm = 123),这是否意味着它是某种自定义类型,指定 db 列名和值? EFCore 如何知道要查询表中的哪一列? EFCore 是否会整理出括号中出现的语法错误? EFCore 是否必须使用括号才能理解查询?

      与 EF Core 无关

      文档选择使用表值函数 dbo.SearchBlogs 来演示原始 SQL 查询的使用,因此 SELECT * FROM [dbo].[SearchBlogs]({0}) 是合法的 SQL,因为 SearchBlogs 是一个函数,而不是表/视图 - 它只是' t 在我链接的文档中提到

      【讨论】:

      • 至少我不是唯一一个发现文档完全混乱的人。
      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 2022-08-21
      • 1970-01-01
      • 2011-03-17
      • 2022-11-11
      • 2021-04-12
      • 2010-11-17
      • 2013-09-09
      相关资源
      最近更新 更多