-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Migrations script: wrap queries in sp_executesql
when using --idempotent
#27729
Comments
The same issue happens with functions. |
@Sjlver You should be able to put the call to |
@ajcvickers Yes, that's absolutely right. I would prefer to not do this for two reasons:
The latter point makes me think that the problem is really with |
I would add that need for changing source migrations can potentially lead to confusing errors later. One may forget to "escape" procedure in migration, and everything will work fine until idempotent migration script has to be applied. It may be really confusing to figure up what is wrong. |
The way this works for other operations is that the SQL generation knows whether an idempotent script is being generated or not. I wonder if we should provide a lambda overload to enable raw SQL operations to do the same... migraionBuilder.Sql(
options =>
{
var sql = "CREATE VIEW MyView AS SELECT 1;";
return options.HasFlag(MigrationsSqlGenerationOptions.Idempotent)
? "sp_execute N'" + sql.Replace("'", "''") + "';"
: sql;
}); |
From what I've seen, users seem to either always uses idempotent migrations, or to never use them - so I'm not sure that would be so useful... The user could also define an extension method which would add the wrapping (e.g. |
Hmm... What's so bad about simply automatically doing the right thing? Why
are we discussing all these options?
As in, there would seem to be no downside at all to my original suggestion.
Dotnet ef migrations would generate correct SQL, and everyone would be
happy. But maybe I'm missing something...
…On Fri, 15 Apr 2022, 18:53 Shay Rojansky, ***@***.***> wrote:
From what I've seen, users seem to either always uses idempotent
migrations, or to never use them - so I'm not sure that would be so
useful... The user could also define an extension method which would add
the wrapping (e.g. migrationBuilder.SqlWithSpExecute(...)), though
there's still of course always the possibility of a dev forgetting to use
it...
—
Reply to this email directly, view it on GitHub
<#27729 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAARS63A6TYTMB3K3QNHK2DVFGUKRANCNFSM5SCFAYUQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
There's a cross-provider aspect to be considered here: sp_execute is SQL Server-specific, and indeed the need to wrap/transform raw migration SQL hasn't popped up in other providers as far as I remember. It's true we could expose a provider hook for transforming raw SQL, and add the sp_execute there for SQL Server. But it's not clear that as a user, I'd want all raw SQL to go through that transformation just because some constructs require it - at the very least it makes migration scripts much less readable etc. Just doing this manually for the few statements that require it may be a good-enough solution. |
Isn't I think the advantages are stronger than the disadvantages here:
|
--idempotent as a feature isn't provider-specific, but there are indeed hooks that provider to specify their At the end of the day, when specifying raw SQL, it's the user's responsibility to provide correct SQL. It's true that in this case the SQL is correct and there's unfortunate incompatibility between idempotent and certain statements (CREATE VIEW); so it's a matter of whether it makes sense to pass all SQL Server raw SQL, always, through sp_executesql, just because of this. It seems trivial enough for the user to work around this, although the discoverability of the workaround isn't great (I think we'd definitely add docs on this). Note: I don't think there's a need for a variable as shown in the OP solution above - the following simpler version should work: EXECUTE sp_executesql N'create view MyView as select 1 as foo'; |
@roji That all makes sense. I'm just wondering why we would want to put the burden on the user (and write docs, and answer the occasional question if users don't find the docs, etc.). Is the increase in complexity of the raw SQL feature really so large as to outweigh the benefits for the users? It might well be; I don't know how the feature is implemented... but my hunch is that it would probably be less than 30 LOC to add a call to Anyway, at this point I feel like I've been vocal enough ;-) Let me just use this opportunity to express my gratitude to EF. It's a great software, and I shudder when I think of previous projects that used stored procedures instead of an ORM... so: thank you! |
This is old known issue: #24045 really frustrating. |
This affects stored procedure create/alter scripts as well. |
In my case it impacted an UPDATE. Basically before the migration i had 1 field, while at the end i needed to split that field in 2 new fields. The migration worked the first time, but from that moment onwards the script would fail because the old column does not exists anymore |
FWIW, I've worked with multiple teams who wanted to begin using an idempotent script on existing projects. And this issue has consistently been a source of pain in those scenarios. |
Hi, I've added the following extension method to my project to easily wrap the statement with executesql: public static OperationBuilder<SqlOperation> SpExecuteSql(this MigrationBuilder builder,
string query, bool suppressTransaction = false)
{
return builder.Sql($"EXECUTE sp_executesql N'{query.Replace("'", "''")}'", suppressTransaction);
} usage: migrationBuilder.SpExecuteSql("""
CREATE VIEW [schema].[viewname] AS
(
SELECT column
FROM table
)
"""); |
I use the following extension method
|
What problem are you trying to solve?
When generating migration scripts with
dotnet ef migrations script --idempotent
, the tool generates invalid SQL in some cases. Consider the following migration:This results in the following migration script:
This script is invalid because
create view
must be the only statement in an SQL query batch; it cannot appear insideIF
.Describe the solution you'd like
The easiest solution seems to me to wrap custom SQL inside
sp_executesql
. Something like this:This works for Microsoft SQL server -- I'm sure other dialects have their own equivalent of dynamic SQL.
The text was updated successfully, but these errors were encountered: