forked from PhenX/PhenX.EntityFrameworkCore.BulkInsert
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOracleBulkInsertProvider.cs
More file actions
129 lines (106 loc) · 4.45 KB
/
Copy pathOracleBulkInsertProvider.cs
File metadata and controls
129 lines (106 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Oracle.ManagedDataAccess.Client;
using PhenX.EntityFrameworkCore.BulkInsert.Metadata;
using PhenX.EntityFrameworkCore.BulkInsert.Options;
namespace PhenX.EntityFrameworkCore.BulkInsert.Oracle;
[UsedImplicitly]
internal class OracleBulkInsertProvider(ILogger<OracleBulkInsertProvider>? logger) : BulkInsertProviderBase<OracleDialectBuilder, OracleBulkInsertOptions>(logger)
{
/// <inheritdoc />
protected override string BulkInsertId => "ROWID";
/// <inheritdoc />
protected override string AddTableCopyBulkInsertId => ""; // No need to add an ID column in Oracle
/// <inheritdoc />
/// <summary>
/// The temporary table name is generated with a random 8-character suffix to ensure uniqueness, and is limited to less than 30 characters,
/// because Oracle prior to 12.2 has a limit of 30 characters for identifiers.
/// </summary>
protected override string GetTempTableName(string tableName) => $"#temp_bulk_insert_{Helpers.RandomString(8)}";
protected override OracleBulkInsertOptions CreateDefaultOptions() => new()
{
BatchSize = 50_000,
};
/// <inheritdoc />
protected override IAsyncEnumerable<T> BulkInsertReturnEntities<T>(
bool sync,
DbContext context,
TableMetadata tableInfo,
IEnumerable<T> entities,
OracleBulkInsertOptions options,
OnConflictOptions<T>? onConflict,
CancellationToken ctk)
{
throw new NotSupportedException("Provider does not support returning entities.");
}
/// <inheritdoc />
protected override Task BulkInsert<T>(
bool sync,
DbContext context,
TableMetadata tableInfo,
IEnumerable<T> entities,
string tableName,
IReadOnlyList<ColumnMetadata> columns,
OracleBulkInsertOptions options,
CancellationToken ctk)
{
var connection = (OracleConnection) context.Database.GetDbConnection();
using var bulkCopy = new OracleBulkCopy(connection, options.CopyOptions);
// When tableName is the SQL-quoted fully qualified name (direct insert path), use the
// unquoted plain table name so ODP.NET does not apply double schema qualification
// (e.g. SchemaX.SchemaX.TABLE_NAME) when a default schema is configured via HasDefaultSchema.
var destinationTableName = tableName == tableInfo.QuotedTableName
? tableInfo.TableName
: tableName;
bulkCopy.DestinationTableName = destinationTableName;
bulkCopy.BatchSize = options.BatchSize;
bulkCopy.BulkCopyTimeout = options.GetCopyTimeoutInSeconds();
// Handle progress notifications
if (options is { NotifyProgressAfter: not null, OnProgress: not null })
{
bulkCopy.NotifyAfter = options.NotifyProgressAfter.Value;
bulkCopy.OracleRowsCopied += (sender, e) =>
{
options.OnProgress(e.RowsCopied);
if (ctk.IsCancellationRequested)
{
e.Abort = true;
}
};
}
// If no progress notification is set, we still need to handle cancellation.
else
{
bulkCopy.OracleRowsCopied += (sender, e) =>
{
if (ctk.IsCancellationRequested)
{
e.Abort = true;
}
};
}
foreach (var column in columns)
{
bulkCopy.ColumnMappings.Add(column.PropertyName, column.QuotedColumName);
}
var dataReader = new EnumerableDataReader<T>(entities, columns, options);
bulkCopy.WriteToServer(dataReader);
return Task.CompletedTask;
}
/// <inheritdoc />
protected override async Task DropTempTableAsync(bool sync, DbContext dbContext, string tableName)
{
var commandText = $"""
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE {tableName}';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN -- ORA-00942: table or view does not exist
RAISE;
END IF;
END;
""";
await ExecuteAsync(sync, dbContext, commandText, CancellationToken.None);
}
}