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

Are EF Core 3.1 ExecuteSqlRaw / ExecuteSqlRawAsync drop-in replacements for ExecuteSqlCommand / ExecuteSqlCommandAsync?

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

Warning CS0618 'RelationalDatabaseFacadeExtensions.ExecuteSqlCommandAsync(DatabaseFacade, RawSqlString, params object[])' is obsolete: 'For the async execution of SQL queries using plain strings, use ExecuteSqlRawAsync instead. For the async execution of SQL queries using interpolated string syntax to create parameters, use ExecuteSqlInterpolatedAsync instead.'

Warning CS0618 'RelationalDatabaseFacadeExtensions.ExecuteSqlCommand(DatabaseFacade, RawSqlString, params object[])' is obsolete: 'For the execution of SQL queries using plain strings, use ExecuteSqlRaw instead. For the execution of SQL queries using interpolated string syntax to create parameters, use ExecuteSqlInterpolated instead.'

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

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 服务器参数 @somename 根本没有讨论,事实上我什至没有看到文档中的示例代码,在哪里他们显示在 table 名称后打开一个括号,是有效的 SQL 语法:

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

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

最终我的问题是:考虑到我的 ExecuteSqlCommand 代码是有意义的,并且 ExecuteSqlRaw 的文档解释得很少 sense/seem,我们如何从这个工作代码开始:

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

要使用 ExecuteSqlRaw?

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

规则很简单。

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.

具有完全相同的行为

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

您可以在 EF Core 3.0 重大更改中阅读有关推理的更多信息 - 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

I didn't see where the docs ever define the contents of the userSuppliedSearchTerm variable or its type, and I'm struggling to see how it could be sensibly a nugget of SQL (string userSuppliedSearchTerm = "WHERE id = 123"; with baked in values? SQL Injection?) or a single primitive value (int userSuppliedSearchTerm = 123) so does it mean it's some kind of custom type that specifies the db column name and the value ? How does EFCore know which column from the table is to be queried? Does EFCore sort out the syntax error presented by the parentheses? Are the parentheses mandatory for EFCore to understand the query?

与 EF Core 无关

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