Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

Upon upgrade to EFCore 3.1 deprecated warnings appeared:

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.'

The old code to which they relate looks like:

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

Consulting the fine manual, typical SQL Server parameters @somename aren't discussed at all, and in fact I don't even see how the example code in the docs, where they show opening a parenthesis after a table name, is valid SQL syntax:

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

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?

Ultimately my question is: given that my ExecuteSqlCommand code made sense, and the docs for ExecuteSqlRaw make little sense/seem poorly explained, how do we go from this working code:

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

To using ExecuteSqlRaw?

SomeType x = ???; context.Database.ExecuteSqlRaw("???", x); 
like image 636
Caius Jard Avatar asked Jan 09 '20 11:01

Caius Jard


People also ask

What is ExecuteSqlRaw?

ExecuteSqlRaw(DatabaseFacade, String, IEnumerable<Object>) Executes the given SQL against the database and returns the number of rows affected. Note that this method does not start a transaction. To use this method with a transaction, first call BeginTransaction(DatabaseFacade, IsolationLevel) or UseTransaction.

Is EF core fast?

EF Core 6.0 performance is now 70% faster on the industry-standard TechEmpower Fortunes benchmark, compared to 5.0. This is the full-stack perf improvement, including improvements in the benchmark code, the . NET runtime, etc. EF Core 6.0 itself is 31% faster executing queries.


2 Answers

The rule is simple.

EF Core 2.x has 3 ExecuteSqlCommand overloads:

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 

which in EF Core 3.x are mapped to

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 

Functionally they are fully equivalent. Raw overloads supports the same placeholders and parameter values (both named and unnamed) as v2.x overloads #1 and #2. And Interpolated has the exact same behavior as the v2.x overload #3.

The reason for renaming the method and using different names for interpolated and non interpolated sql parameter is the C# compile time overload resolution for v2.x overloads #1 and #3. Sometimes it chooses interpolated when the intent was to use the other one, and vise versa. Having separate names makes intent clear.

You can read more about the reasoning in EF Core 3.0 Breaking Changes - FromSql, ExecuteSql, and ExecuteSqlAsync have been renamed.

The information about supported parameter placeholders,names and values can be found in Raw SQL queries - Passing parameters.

But to answer your concrete question, if the existing v2.x code is

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

then change it to ExecuteSqlRaw.

And if was

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

then change it to ExecuteSqlInterpolated.

like image 90
Ivan Stoev Avatar answered Oct 11 '22 18:10

Ivan Stoev


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?

All nothing to do with EF Core

The docs have chosen to use a Table Valued Function dbo.SearchBlogs to demonstrate the use of raw SQL querying, so SELECT * FROM [dbo].[SearchBlogs]({0}) is legal SQL because SearchBlogs is a function, not a table/view - it just wasn't mentioned on the docs I linked

like image 34
Caius Jard Avatar answered Oct 11 '22 17:10

Caius Jard