Skip to content

Commit 4ccd795

Browse files
authored
Merge pull request #101 from microting/copilot/implement-custom-override-methods
Override RETURNING operation methods for EF Core 10 compatibility
2 parents 5cecf55 + c94cf77 commit 4ccd795

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,45 @@ public override ResultSetMapping AppendInsertOperation(
3838
? AppendInsertReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction)
3939
: base.AppendInsertOperation(commandStringBuilder, command, commandPosition, out requiresTransaction);
4040

41+
/// <summary>
42+
/// Appends SQL for inserting a row to the commands being built, via an INSERT containing a RETURNING clause
43+
/// to retrieve any database-generated values.
44+
/// </summary>
45+
/// <param name="commandStringBuilder">The builder to which the SQL should be appended.</param>
46+
/// <param name="command">The command that represents the insert operation.</param>
47+
/// <param name="commandPosition">The ordinal of this command in the batch.</param>
48+
/// <param name="requiresTransaction">Returns whether the SQL appended must be executed in a transaction to work correctly.</param>
49+
/// <returns>The <see cref="ResultSetMapping" /> for the command.</returns>
50+
public override ResultSetMapping AppendInsertReturningOperation(
51+
StringBuilder commandStringBuilder,
52+
IReadOnlyModificationCommand command,
53+
int commandPosition,
54+
out bool requiresTransaction)
55+
{
56+
var name = command.TableName;
57+
var schema = command.Schema;
58+
var operations = command.ColumnModifications;
59+
60+
var writeOperations = operations.Where(o => o.IsWrite).ToList();
61+
var readOperations = operations.Where(o => o.IsRead).ToList();
62+
63+
AppendInsertCommandHeader(commandStringBuilder, name, schema, writeOperations);
64+
AppendValuesHeader(commandStringBuilder, writeOperations);
65+
AppendValues(commandStringBuilder, name, schema, writeOperations);
66+
67+
// MySQL supports RETURNING clause starting from version 8.0.21
68+
if (_options.ServerVersion.Supports.Returning && readOperations.Count > 0)
69+
{
70+
AppendReturningClause(commandStringBuilder, readOperations);
71+
}
72+
73+
commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator);
74+
75+
requiresTransaction = false;
76+
77+
return readOperations.Count > 0 ? ResultSetMapping.LastInResultSet : ResultSetMapping.NoResults;
78+
}
79+
4180
public virtual ResultSetMapping AppendBulkInsertOperation(
4281
StringBuilder commandStringBuilder,
4382
IReadOnlyList<IReadOnlyModificationCommand> modificationCommands,
@@ -137,6 +176,58 @@ protected override void AppendValues(
137176
}
138177
}
139178

179+
public override ResultSetMapping AppendUpdateOperation(
180+
StringBuilder commandStringBuilder,
181+
IReadOnlyModificationCommand command,
182+
int commandPosition,
183+
out bool requiresTransaction)
184+
=> _options.ServerVersion.Supports.Returning
185+
? AppendUpdateReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction)
186+
: base.AppendUpdateOperation(commandStringBuilder, command, commandPosition, out requiresTransaction);
187+
188+
/// <summary>
189+
/// Appends SQL for updating a row to the commands being built, via an UPDATE containing a RETURNING clause
190+
/// to retrieve any database-generated values or for concurrency checking.
191+
/// </summary>
192+
/// <param name="commandStringBuilder">The builder to which the SQL should be appended.</param>
193+
/// <param name="command">The command that represents the update operation.</param>
194+
/// <param name="commandPosition">The ordinal of this command in the batch.</param>
195+
/// <param name="requiresTransaction">Returns whether the SQL appended must be executed in a transaction to work correctly.</param>
196+
/// <returns>The <see cref="ResultSetMapping" /> for the command.</returns>
197+
protected override ResultSetMapping AppendUpdateReturningOperation(
198+
StringBuilder commandStringBuilder,
199+
IReadOnlyModificationCommand command,
200+
int commandPosition,
201+
out bool requiresTransaction)
202+
{
203+
var name = command.TableName;
204+
var schema = command.Schema;
205+
var operations = command.ColumnModifications;
206+
207+
var writeOperations = operations.Where(o => o.IsWrite).ToList();
208+
var conditionOperations = operations.Where(o => o.IsCondition).ToList();
209+
var readOperations = operations.Where(o => o.IsRead).ToList();
210+
211+
requiresTransaction = false;
212+
213+
var anyReadOperations = readOperations.Count > 0;
214+
215+
AppendUpdateCommandHeader(commandStringBuilder, name, schema, writeOperations);
216+
AppendWhereClause(commandStringBuilder, conditionOperations);
217+
218+
// MySQL supports RETURNING clause starting from version 8.0.21
219+
if (_options.ServerVersion.Supports.Returning)
220+
{
221+
AppendReturningClause(commandStringBuilder, readOperations, anyReadOperations ? null : "1");
222+
}
223+
224+
commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator);
225+
226+
return anyReadOperations
227+
? ResultSetMapping.LastInResultSet
228+
: ResultSetMapping.LastInResultSet | ResultSetMapping.ResultSetWithRowsAffectedOnly;
229+
}
230+
140231
public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder,
141232
IReadOnlyModificationCommand command,
142233
int commandPosition,
@@ -145,6 +236,41 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri
145236
? AppendDeleteReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction)
146237
: base.AppendDeleteOperation(commandStringBuilder, command, commandPosition, out requiresTransaction);
147238

239+
/// <summary>
240+
/// Appends SQL for deleting a row to the commands being built, via a DELETE containing a RETURNING clause
241+
/// for concurrency checking.
242+
/// </summary>
243+
/// <param name="commandStringBuilder">The builder to which the SQL should be appended.</param>
244+
/// <param name="command">The command that represents the delete operation.</param>
245+
/// <param name="commandPosition">The ordinal of this command in the batch.</param>
246+
/// <param name="requiresTransaction">Returns whether the SQL appended must be executed in a transaction to work correctly.</param>
247+
/// <returns>The <see cref="ResultSetMapping" /> for the command.</returns>
248+
protected override ResultSetMapping AppendDeleteReturningOperation(
249+
StringBuilder commandStringBuilder,
250+
IReadOnlyModificationCommand command,
251+
int commandPosition,
252+
out bool requiresTransaction)
253+
{
254+
var name = command.TableName;
255+
var schema = command.Schema;
256+
var conditionOperations = command.ColumnModifications.Where(o => o.IsCondition).ToList();
257+
258+
requiresTransaction = false;
259+
260+
AppendDeleteCommandHeader(commandStringBuilder, name, schema);
261+
AppendWhereClause(commandStringBuilder, conditionOperations);
262+
263+
// MySQL supports RETURNING clause starting from version 8.0.21
264+
if (_options.ServerVersion.Supports.Returning)
265+
{
266+
AppendReturningClause(commandStringBuilder, [], "1");
267+
}
268+
269+
commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator);
270+
271+
return ResultSetMapping.LastInResultSet | ResultSetMapping.ResultSetWithRowsAffectedOnly;
272+
}
273+
148274
protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string schema, int commandPosition)
149275
{
150276
commandStringBuilder

0 commit comments

Comments
 (0)