Skip to content

Fix RawSql backward compatibility in DELETE and UPDATE WHERE clauses#2199

Merged
jzabroski merged 4 commits into
mainfrom
copilot/fix-delete-from-table-issue
Dec 1, 2025
Merged

Fix RawSql backward compatibility in DELETE and UPDATE WHERE clauses#2199
jzabroski merged 4 commits into
mainfrom
copilot/fix-delete-from-table-issue

Conversation

Copilot AI commented Dec 1, 2025

Copy link
Copy Markdown
Contributor
  • Analyzed the issue: Breaking change in PR Bugfix/1827 raw sql #1904 where RawSql.Insert("(SELECT...)") in Delete/Update WHERE clauses no longer adds the = operator automatically
  • Understood the problem: The GenerateWhere method in GenericGenerator.cs now expects the operator to be included in the RawSql value, but old code passed just the value
  • Implemented fix: Detect if RawSql contains an operator, if not, add = by default for backward compatibility
  • Added unit tests for the new behavior covering subqueries, explicit operators, IS NULL, IN, LIKE, and comparison operators (10 tests added in SqlServer2005DataTests)
  • Updated integration tests in MigrationRunnerTests.cs to include backward compatibility scenario (RawSql values without explicit operators)
  • Ran all data tests (277 tests passed)
  • Code review completed

Summary

The fix maintains backward compatibility by detecting whether a RawSql value starts with an operator. If it doesn't, the = operator is automatically added.

Both syntaxes now work:

  • Old syntax: RawSql.Insert("(SELECT...)") or RawSql.Insert("104") - automatically adds = operator
  • New syntax: RawSql.Insert("= 3") or RawSql.Insert("IS NULL") - used as-is
Original prompt

This section details on the original issue you should resolve

<issue_title>Delete.FromTable issue</issue_title>
<issue_description>I have the following in my migration:

Delete.FromTable("RolePermissions").Row(new { PermissionId = RawSql.Insert("(SELECT [Id] FROM [dbo].[Permissions] WHERE [Name] = 'Foo')") });

But since upgrading from 6.2.0 to 7.0.0 it now throws the error:

Exception: An error occurred executing the following sql:
DELETE FROM [dbo].[RolePermissions] WHERE [PermissionId] (SELECT [Id] FROM [dbo].[Permissions] WHERE [Name] = 'Foo')
The error was An expression of non-boolean type specified in a context where a condition is expected, near '('.</issue_description>

<agent_instructions>Look into the breaking change introduced in #1904 - see if there is a way to generalize the behavior of InsertDataExpression, UpdateDataExpression and DeleteDataExpression such that expression generation for all 3 is more consistent across the 3 expression types.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@PhenX Oh, I see the problem, that's a breaking change I did not anticipate when improving RawSql support. That means that anybody using the old supported syntax undergoes this breaking change ...

I see two possible syntaxes for you :

Delete.FromTable("RolePermissions").Row(new { PermissionId = RawSql.Insert("= PermissionId = (SELECT [Id] FROM [dbo].[Permissions] WHERE [Name] = 'Foo')") });

or

Delete.FromTable("RolePermissions").Row("PermissionId = (SELECT [Id] FROM [dbo].[Permissions] WHERE [Name] = 'Foo')");
@PhenX I don't know, it would make a new breaking changge (again) ...

@jzabroski how could we handle it ? Maybe with a configuration ?</comment_new>
<comment_new>@jzabroski
The first answer always has to be to add unit test coverage.

In this case, I am surprised it worked in 6.2.0. Did you confirm? I will probably test it myself in a few hours. </comment_new>
<comment_new>@jzabroski

Do you expect to patch this? To go back and update my migrations across all my sites is likely going to cause a few headaches.

To directly answer your question, if it is a break, yes, I expect to fix it in the upcoming release. This unit test needs updating to capture your usage
https://github.com/fluentmigrator/fluentmigrator/blob/main/test/FluentMigrator.Tests/Integration/MigrationRunnerTests.cs#L2172-L2184</comment_new>
<comment_new>@PhenX
The difference is that before, it used to assume the RawSql contained only what's after the "=", now it needs to contain the operand.</comment_new>
<comment_new>@PhenX
We may need to bring a new "un-breaking" change, in the third syntax of the unit test I guess.</comment_new>
<comment_new>@jzabroski
@PhenX This should be fixable, as he is not relying on the code generating an IN clause. That is something we do not support. I think it can "know" the operand based on whether its a CAR or CDR expression (in Lisp terms). The issue is here basically:

cc22f38#diff-47ff32219b9f01c1320bd7e9dac971767a201a8c36ceb1f7beecbd4aa0e87185L340-R381</comment_new>
<comment_new>@jzabroski
@PhenX Does that help? He is essentially saying InsertDataExpression, DeleteDataExpression and UpdateDataExpression should all have the same behavior with respect to RawSql.Insert, which I think is fair.</comment_new>
<comment_new>@PhenX
One is for a where the other one for a list of values though. But I get why it feels inconsistent </comment_new>
<comment_new>@jzabroski
That is why I think the right solution is to detect whether the expression is inside another object or not. I would need to prototype it myself and cannot right now but I feel like it is possible.</comment_new>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Fix Delete.FromTable issue after migration upgrade Fix RawSql backward compatibility in DELETE and UPDATE WHERE clauses Dec 1, 2025
Copilot AI requested a review from jzabroski December 1, 2025 22:14
@jzabroski

Copy link
Copy Markdown
Collaborator

@copilot You need to update MigrationRunnerTests.cs here

Delete.FromTable("Foo").InSchema("TestSchema")
// DELETE : Raw SQL with string
.Row("baz = 101")
// DELETE : Raw SQL with RawSql object
.Row(RawSql.Insert("baz = 102"))
// DELETE : Raw SQL with RawSql object inside an anonymous object
.Row(new
{
baz = RawSql.Insert("= 103")
});

Copilot AI commented Dec 1, 2025

Copy link
Copy Markdown
Contributor Author

@copilot You need to update MigrationRunnerTests.cs here https://github.com/fluentmigrator/fluentmigrator/blob/fcc42a9cf583f6347b07d76bde48605b506cf4ee/test/FluentMigrator.Tests/Integration/MigrationR...

Updated MigrationRunnerTests.cs with a 4th test case that exercises backward compatibility - using RawSql.Insert("4") and RawSql.Insert("104") without explicit operators in the RawSqlUpdateMigration and RawSqlDeleteMigration classes. Commit e709930.

@jzabroski

Copy link
Copy Markdown
Collaborator

@PhenX This looks good to me. Can you review as well?

@jzabroski
jzabroski requested a review from PhenX December 1, 2025 22:31
@PhenX
PhenX marked this pull request as ready for review December 1, 2025 22:33
@jzabroski jzabroski added this to the 7.2.0 milestone Dec 1, 2025
@github-actions

github-actions Bot commented Dec 1, 2025

Copy link
Copy Markdown

Test Results

    2 files  ±0      2 suites  ±0   38s ⏱️ -1s
5 355 tests ±0  5 023 ✅ +1  332 💤 ±0  0 ❌  - 1 
5 836 runs  ±0  5 240 ✅ +1  596 💤 ±0  0 ❌  - 1 

Results for commit e709930. ± Comparison against base commit fcc42a9.

♻️ This comment has been updated with latest results.

@jzabroski
jzabroski merged commit ec46621 into main Dec 1, 2025
6 checks passed
@jzabroski
jzabroski deleted the copilot/fix-delete-from-table-issue branch December 1, 2025 23:16
@jzabroski

Copy link
Copy Markdown
Collaborator

I published 7.2.0 release notes. I still need to approve it in ADO for official release, but plan is to release 7.2, then publish 8.0 with .NET 10 support in #2181

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete.FromTable issue

3 participants