protected override BulkCopyRowsCopied ProviderSpecificCopy <T>( ITable <T> table, BulkCopyOptions options, IEnumerable <T> source) { // database name is not a part of table FQN in oracle var serverName = options.ServerName ?? table.ServerName; if (table.DataContext is DataConnection dataConnection && _provider.Adapter.BulkCopy != null && serverName == null) { var connection = _provider.TryGetProviderConnection(dataConnection.Connection, dataConnection.MappingSchema); if (connection != null) { var ed = dataConnection.MappingSchema.GetEntityDescriptor(typeof(T)); var columns = ed.Columns.Where(c => !c.SkipOnInsert || options.KeepIdentity == true && c.IsIdentity).ToList(); var sb = _provider.CreateSqlBuilder(dataConnection.MappingSchema); // ODP.NET doesn't bulk copy doesn't work if columns that require escaping: // - if escaping applied, pre-flight validation fails as it performs uppercase comparison and quotes make it fail with // InvalidOperationException: Column mapping is invalid // - if escaping not applied - if fails as expected on server, because it treats passed name as uppercased name // and gives "ORA-00904: "STRINGVALUE": invalid identifier" error // That's quite common error in bulk copy implementation error by providers... var supported = true; foreach (var column in columns) { if (column.ColumnName != sb.ConvertInline(column.ColumnName, ConvertType.NameToQueryField)) { // fallback to sql-based copy // TODO: we should add support for by-ordinal column mapping to workaround it supported = false; break; } } if (supported) { var rd = new BulkCopyReader <T>(dataConnection, columns, source); var sqlopt = OracleProviderAdapter.OracleBulkCopyOptions.Default; var rc = new BulkCopyRowsCopied(); var tableName = sb.ConvertInline(options.TableName ?? table.TableName, ConvertType.NameToQueryTable); var schemaName = options.SchemaName ?? table.SchemaName; if (schemaName != null) { schemaName = sb.ConvertInline(schemaName, ConvertType.NameToSchema); } if (options.UseInternalTransaction == true) { sqlopt |= OracleProviderAdapter.OracleBulkCopyOptions.UseInternalTransaction; } using (var bc = _provider.Adapter.BulkCopy.Create(connection, sqlopt)) { var notifyAfter = options.NotifyAfter == 0 && options.MaxBatchSize.HasValue ? options.MaxBatchSize.Value : options.NotifyAfter; if (notifyAfter != 0 && options.RowsCopiedCallback != null) { bc.NotifyAfter = options.NotifyAfter; bc.OracleRowsCopied += (sender, args) => { rc.RowsCopied = args.RowsCopied; options.RowsCopiedCallback(rc); if (rc.Abort) { args.Abort = true; } }; } if (options.MaxBatchSize.HasValue) { bc.BatchSize = options.MaxBatchSize.Value; } if (options.BulkCopyTimeout.HasValue) { bc.BulkCopyTimeout = options.BulkCopyTimeout.Value; } else if (Configuration.Data.BulkCopyUseConnectionCommandTimeout) { bc.BulkCopyTimeout = connection.ConnectionTimeout; } bc.DestinationTableName = tableName; bc.DestinationSchemaName = schemaName; for (var i = 0; i < columns.Count; i++) { bc.ColumnMappings.Add(_provider.Adapter.BulkCopy.CreateColumnMapping(i, columns[i].ColumnName)); } TraceAction( dataConnection, () => "INSERT BULK " + (schemaName == null ? tableName : schemaName + "." + tableName) + "(" + string.Join(", ", columns.Select(x => x.ColumnName)) + ")" + Environment.NewLine, () => { bc.WriteToServer(rd); return(rd.Count); }); } if (rc.RowsCopied != rd.Count) { rc.RowsCopied = rd.Count; if (options.NotifyAfter != 0 && options.RowsCopiedCallback != null) { options.RowsCopiedCallback(rc); } } return(rc); } } } return(MultipleRowsCopy(table, options, source)); }
protected override BulkCopyRowsCopied ProviderSpecificCopy <T>( ITable <T> table, BulkCopyOptions options, IEnumerable <T> source) { if (table.DataContext is DataConnection dataConnection && dataConnection.Transaction == null && _provider.Adapter.BulkCopy != null) { var connection = _provider.TryGetProviderConnection(dataConnection.Connection, dataConnection.MappingSchema); if (connection != null) { var ed = dataConnection.MappingSchema.GetEntityDescriptor(typeof(T)); var columns = ed.Columns.Where(c => !c.SkipOnInsert || options.KeepIdentity == true && c.IsIdentity).ToList(); var sb = _provider.CreateSqlBuilder(dataConnection.MappingSchema); var rd = new BulkCopyReader <T>(dataConnection, columns, source); var sqlopt = OracleProviderAdapter.OracleBulkCopyOptions.Default; var rc = new BulkCopyRowsCopied(); var tableName = GetTableName(sb, options, table); if (options.UseInternalTransaction == true) { sqlopt |= OracleProviderAdapter.OracleBulkCopyOptions.UseInternalTransaction; } using (var bc = _provider.Adapter.BulkCopy.Create(connection, sqlopt)) { var notifyAfter = options.NotifyAfter == 0 && options.MaxBatchSize.HasValue ? options.MaxBatchSize.Value : options.NotifyAfter; if (notifyAfter != 0 && options.RowsCopiedCallback != null) { bc.NotifyAfter = options.NotifyAfter; bc.OracleRowsCopied += (sender, args) => { rc.RowsCopied = args.RowsCopied; options.RowsCopiedCallback(rc); if (rc.Abort) { args.Abort = true; } }; } if (options.MaxBatchSize.HasValue) { bc.BatchSize = options.MaxBatchSize.Value; } if (options.BulkCopyTimeout.HasValue) { bc.BulkCopyTimeout = options.BulkCopyTimeout.Value; } else if (Configuration.Data.BulkCopyUseConnectionCommandTimeout) { bc.BulkCopyTimeout = connection.ConnectionTimeout; } bc.DestinationTableName = tableName; for (var i = 0; i < columns.Count; i++) { bc.ColumnMappings.Add(_provider.Adapter.BulkCopy.CreateColumnMapping(i, columns[i].ColumnName)); } TraceAction( dataConnection, () => "INSERT BULK " + tableName + "(" + string.Join(", ", columns.Select(x => x.ColumnName)) + Environment.NewLine, () => { bc.WriteToServer(rd); return(rd.Count); }); } if (rc.RowsCopied != rd.Count) { rc.RowsCopied = rd.Count; if (options.NotifyAfter != 0 && options.RowsCopiedCallback != null) { options.RowsCopiedCallback(rc); } } return(rc); } } return(MultipleRowsCopy(table, options, source)); }
protected override BulkCopyRowsCopied ProviderSpecificCopy <T>( [JetBrains.Annotations.NotNull] DataConnection dataConnection, BulkCopyOptions options, IEnumerable <T> source) { if (dataConnection == null) { throw new ArgumentNullException("dataConnection"); } var sqlBuilder = _dataProvider.CreateSqlBuilder(); var descriptor = dataConnection.MappingSchema.GetEntityDescriptor(typeof(T)); var tableName = GetTableName(sqlBuilder, descriptor); if (dataConnection.Transaction == null) { if (_bulkCopyCreator == null) { var clientNamespace = OracleTools.AssemblyName + ".Client."; var bulkCopyType = _connectionType.Assembly.GetType(clientNamespace + "OracleBulkCopy", false); var bulkCopyOptionType = _connectionType.Assembly.GetType(clientNamespace + "OracleBulkCopyOptions", false); var columnMappingType = _connectionType.Assembly.GetType(clientNamespace + "OracleBulkCopyColumnMapping", false); if (bulkCopyType != null) { _bulkCopyCreator = CreateBulkCopyCreator(_connectionType, bulkCopyType, bulkCopyOptionType); _columnMappingCreator = CreateColumnMappingCreator(columnMappingType); } } if (_bulkCopyCreator != null) { var columns = descriptor.Columns.Where(c => !c.SkipOnInsert).ToList(); var rd = new BulkCopyReader(_dataProvider, columns, source); var rc = new BulkCopyRowsCopied(); var bcOptions = 0; // Default if (options.UseInternalTransaction == true) { bcOptions |= 1; // UseInternalTransaction = 1, } using (var bc = _bulkCopyCreator(dataConnection.Connection, bcOptions)) { dynamic dbc = bc; var notifyAfter = options.NotifyAfter == 0 && options.MaxBatchSize.HasValue ? options.MaxBatchSize.Value : options.NotifyAfter; if (notifyAfter != 0 && options.RowsCopiedCallback != null) { if (_bulkCopySubscriber == null) { _bulkCopySubscriber = CreateBulkCopySubscriber(bc, "OracleRowsCopied"); } dbc.NotifyAfter = notifyAfter; _bulkCopySubscriber(bc, arg => { dynamic darg = arg; rc.RowsCopied = darg.RowsCopied; options.RowsCopiedCallback(rc); if (rc.Abort) { darg.Abort = true; } }); } if (options.MaxBatchSize.HasValue) { dbc.BatchSize = options.MaxBatchSize.Value; } if (options.BulkCopyTimeout.HasValue) { dbc.BulkCopyTimeout = options.BulkCopyTimeout.Value; } dbc.DestinationTableName = tableName; for (var i = 0; i < columns.Count; i++) { dbc.ColumnMappings.Add((dynamic)_columnMappingCreator(i, columns[i].ColumnName)); } dbc.WriteToServer(rd); } rc.RowsCopied = rd.Count; return(rc); } } return(MultipleRowsCopy(dataConnection, options, source)); }