EF Core 3.1 ExecuteSqlRaw / ExecuteSqlRawAsync 是 ExecuteSqlCommand / ExecuteSqlCommandAsync 的替代品吗?

Cai*_*ard 18 c# entity-framework-core ef-core-3.1

升级到 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);
Run Code Online (Sandbox Code Playgroud)

查阅精美手册@somename根本没有讨论典型的 SQL Server 参数,实际上我什至看不到文档中的示例代码(它们显示在表名后打开括号)是有效的 SQL 语法:

context.Database.ExecuteSqlRaw("SELECT * FROM [dbo].[SearchBlogs]({0})", userSuppliedSearchTerm)
Run Code Online (Sandbox Code Playgroud)

我没有看到文档在哪里定义了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);
Run Code Online (Sandbox Code Playgroud)

使用 ExecuteSqlRaw?

SomeType x = ???;
context.Database.ExecuteSqlRaw("???", x);
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 32

规则很简单。

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
Run Code Online (Sandbox Code Playgroud)

在 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
Run Code Online (Sandbox Code Playgroud)

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

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

您可以在 EF Core 3.0 Breaking Changes - FromSql、ExecuteSql 和 ExecuteSqlAsync 已重命名中阅读有关推理的更多信息。

有关支持的参数占位符、名称和值的信息可以在原始 SQL 查询 - 传递参数中找到

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

context.Database.ExecuteSqlCommand("DELETE FROM Table WHERE ID = @p0", id);
Run Code Online (Sandbox Code Playgroud)

然后将其更改为ExecuteSqlRaw.

如果是

context.Database.ExecuteSqlCommand($"DELETE FROM Table WHERE ID = {id}");
Run Code Online (Sandbox Code Playgroud)

然后将其更改为ExecuteSqlInterpolated.


Cai*_*ard 4

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

与 EF Core 无关

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

  • 至少我不是唯一一个发现文档完全令人困惑的人。 (14认同)