diff --git a/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleDialectBuilder.cs b/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleDialectBuilder.cs index 60d4b3b..40de402 100644 --- a/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleDialectBuilder.cs +++ b/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleDialectBuilder.cs @@ -49,41 +49,48 @@ public override string BuildMoveDataSql( throw new InvalidOperationException("Table has no primary key that can be used for conflict detection."); } - q.AppendLine($"MERGE INTO {target.QuotedTableName} AS {PseudoTableInserted}"); + q.AppendLine($"MERGE INTO {target.QuotedTableName} {PseudoTableInserted}"); q.Append("USING (SELECT "); q.AppendColumns(insertedColumns); - q.Append($" FROM {source}) AS {PseudoTableExcluded} ("); - q.AppendColumns(insertedColumns); - q.AppendLine(")"); - - q.Append("ON "); - q.AppendJoin(" AND ", matchColumns, (b, col) => b.Append($"{PseudoTableInserted}.{col} = {PseudoTableExcluded}.{col}")); + q.Append($" FROM {source}) {PseudoTableExcluded}"); q.AppendLine(); - if (onConflictTyped.Update != null) - { - var columns = target.GetColumns(false); - - q.AppendLine("WHEN MATCHED THEN UPDATE SET "); - q.AppendJoin(", ", GetUpdates(context, target, columns, onConflictTyped.Update)); - q.AppendLine(); - } + q.Append("ON ("); + q.AppendJoin(" AND ", matchColumns, (b, col) => b.Append($"{PseudoTableInserted}.{col} = {PseudoTableExcluded}.{col}")); + q.AppendLine(")"); + // WHEN NOT MATCHED clause should come before WHEN MATCHED in Oracle q.Append("WHEN NOT MATCHED THEN INSERT ("); q.AppendColumns(insertedColumns); q.AppendLine(")"); q.Append("VALUES ("); q.AppendJoin(", ", insertedColumns, (b, col) => b.Append($"{PseudoTableExcluded}.{col.QuotedColumName}")); - q.AppendLine(")"); + q.Append(")"); - if (returnedColumns.Count != 0) + if (onConflictTyped.Update != null) { - q.Append("OUTPUT "); - q.AppendJoin(", ", returnedColumns, (b, col) => b.Append($"{PseudoTableInserted}.{col.QuotedColumName} AS {col.QuotedColumName}")); - q.AppendLine(); + var columns = target.GetColumns(false); + + q.Append(" WHEN MATCHED"); + + if (onConflictTyped.RawWhere != null || onConflictTyped.Where != null) + { + if (onConflictTyped is { RawWhere: not null, Where: not null }) + { + throw new ArgumentException("Cannot specify both RawWhere and Where in OnConflictOptions."); + } + + q.Append(" AND "); + AppendConflictCondition(q, target, context, onConflictTyped); + } + + q.Append(" THEN UPDATE SET "); + q.AppendJoin(", ", GetUpdates(context, target, columns, onConflictTyped.Update)); } + + q.AppendLine(); } // No conflict handling diff --git a/tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/Tests/Merge/MergeTestsOracle.cs b/tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/Tests/Merge/MergeTestsOracle.cs new file mode 100644 index 0000000..86dc10d --- /dev/null +++ b/tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/Tests/Merge/MergeTestsOracle.cs @@ -0,0 +1,12 @@ +using PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContainer; +using PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext; + +using Xunit; + +namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.Tests.Merge; + +[Trait("Category", "Oracle")] +[Collection(TestDbContainerOracleCollection.Name)] +public class MergeTestsOracle(TestDbContainerOracle dbContainer) : MergeTestsBase(dbContainer) +{ +}