From a3743ef4811376b9d9873be20e71713fedba4ed4 Mon Sep 17 00:00:00 2001 From: Pschichholz Date: Wed, 6 May 2026 15:43:51 +0200 Subject: [PATCH 1/2] Fix Oracle bulk insert schema qualification issues (#1) - Fix double-schema qualification when EF Core default schema is configured - Clarify table name handling comment --- .../OracleBulkInsertProvider.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleBulkInsertProvider.cs b/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleBulkInsertProvider.cs index b97feab..d58c915 100644 --- a/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleBulkInsertProvider.cs +++ b/src/PhenX.EntityFrameworkCore.BulkInsert.Oracle/OracleBulkInsertProvider.cs @@ -59,7 +59,14 @@ protected override Task BulkInsert( using var bulkCopy = new OracleBulkCopy(connection, options.CopyOptions); - bulkCopy.DestinationTableName = tableName; + // 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(); From 901cb2837fa2a31a16a2e5259de494bcf786c914 Mon Sep 17 00:00:00 2001 From: Pschichholz Date: Wed, 6 May 2026 16:27:15 +0200 Subject: [PATCH 2/2] Add OpenTelemetry instrumentation project and update README --- PhenX.EntityFrameworkCore.BulkInsert.slnx | 1 + README.md | 4 + docs/.vitepress/config.mts | 6 ++ docs/opentelemetry.md | 87 +++++++++++++++++++ ...henX.EntityFrameworkCore.BulkInsert.csproj | 5 ++ .../TracerProviderBuilderExtensions.cs | 18 ++++ 6 files changed, 121 insertions(+) create mode 100644 docs/opentelemetry.md create mode 100644 src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert.csproj create mode 100644 src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/TracerProviderBuilderExtensions.cs diff --git a/PhenX.EntityFrameworkCore.BulkInsert.slnx b/PhenX.EntityFrameworkCore.BulkInsert.slnx index 4697239..7555761 100644 --- a/PhenX.EntityFrameworkCore.BulkInsert.slnx +++ b/PhenX.EntityFrameworkCore.BulkInsert.slnx @@ -14,6 +14,7 @@ + diff --git a/README.md b/README.md index 7df4e90..f5aa86c 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ but they are in [the roadmap](#roadmap). | `PhenX.EntityFrameworkCore.BulkInsert.MySql` | For MySql | [![NuGet](https://img.shields.io/nuget/v/PhenX.EntityFrameworkCore.BulkInsert.Sqlite.svg)](https://www.nuget.org/packages/PhenX.EntityFrameworkCore.BulkInsert.MySql) | | `PhenX.EntityFrameworkCore.BulkInsert.Oracle` | For Oracle | [![NuGet](https://img.shields.io/nuget/v/PhenX.EntityFrameworkCore.BulkInsert.Oracle.svg)](https://www.nuget.org/packages/PhenX.EntityFrameworkCore.BulkInsert.Oracle) | | `PhenX.EntityFrameworkCore.BulkInsert` | Common library | [![NuGet](https://img.shields.io/nuget/v/PhenX.EntityFrameworkCore.BulkInsert.svg)](https://www.nuget.org/packages/PhenX.EntityFrameworkCore.BulkInsert) | +| `OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert` | OpenTelemetry instrumentation | [![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert) | ### Dependencies @@ -51,6 +52,9 @@ Install-Package PhenX.EntityFrameworkCore.BulkInsert.MySql # For Oracle Install-Package PhenX.EntityFrameworkCore.BulkInsert.Oracle + +# For OpenTelemetry instrumentation +Install-Package OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert ``` ## Usage diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 66a5c4f..65777c3 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -48,6 +48,12 @@ export default defineConfig({ { text: 'Documentation', link: '/documentation', + items: [ + { + text: 'OpenTelemetry', + link: '/opentelemetry', + }, + ], }, { text: 'Limitations', diff --git a/docs/opentelemetry.md b/docs/opentelemetry.md new file mode 100644 index 0000000..e9e1d7b --- /dev/null +++ b/docs/opentelemetry.md @@ -0,0 +1,87 @@ +--- +title: OpenTelemetry Instrumentation +lang: en-US +--- + +# OpenTelemetry Instrumentation + +PhenX.EntityFrameworkCore.BulkInsert has built-in support for [OpenTelemetry](https://opentelemetry.io/) tracing via the `OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert` package. + +Each bulk insert operation is automatically tracked as an [Activity](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.activity) using the `PhenX.EntityFrameworkCore.BulkInsert` activity source, enabling distributed tracing and performance monitoring in your application. + +## Installation + +Install the instrumentation NuGet package: + +```shell +Install-Package OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert +``` + +## Configuration + +Register the instrumentation when configuring your OpenTelemetry `TracerProvider` by calling `AddPhenXEntityFrameworkCoreBulkInsertInstrumentation()`: + +```csharp +using OpenTelemetry.Trace; + +builder.Services.AddOpenTelemetry() + .WithTracing(tracing => tracing + .AddAspNetCoreInstrumentation() + .AddPhenXEntityFrameworkCoreBulkInsertInstrumentation() // <-- add this + .AddOtlpExporter() + ); +``` + +## `TracerProviderBuilderExtensions` + +### `AddPhenXEntityFrameworkCoreBulkInsertInstrumentation` + +```csharp +public static TracerProviderBuilder AddPhenXEntityFrameworkCoreBulkInsertInstrumentation( + this TracerProviderBuilder builder) +``` + +Adds the `PhenX.EntityFrameworkCore.BulkInsert` activity source to the given `TracerProviderBuilder`. + +**Parameters** + +| Parameter | Type | Description | +|-----------|------------------------|-----------------------------------------------------------| +| `builder` | `TracerProviderBuilder` | The `TracerProviderBuilder` to add the instrumentation to. | + +**Returns** + +The `TracerProviderBuilder` with the `PhenX.EntityFrameworkCore.BulkInsert` instrumentation registered. + +## Traced Operations + +The following bulk insert operations produce OpenTelemetry traces: + +| Operation | Description | +|--------------------------------------|----------------------------------------------------------| +| `ExecuteBulkInsert` | Synchronous bulk insert without entity return | +| `ExecuteBulkInsertAsync` | Asynchronous bulk insert without entity return | +| `ExecuteBulkInsertReturnEntities` | Synchronous bulk insert with entity return | +| `ExecuteBulkInsertReturnEntitiesAsync` | Asynchronous bulk insert with entity return | + +## Activity Source + +The activity source name used by this library is: + +``` +PhenX.EntityFrameworkCore.BulkInsert +``` + +You can use this name to subscribe directly to the activity source if you need lower-level access: + +```csharp +using System.Diagnostics; + +ActivitySource.AddActivityListener(new ActivityListener +{ + ShouldListenTo = source => source.Name == "PhenX.EntityFrameworkCore.BulkInsert", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, + ActivityStarted = activity => Console.WriteLine($"Started: {activity.DisplayName}"), + ActivityStopped = activity => Console.WriteLine($"Stopped: {activity.DisplayName} ({activity.Duration})"), +}); +``` diff --git a/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert.csproj b/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert.csproj new file mode 100644 index 0000000..09a57f5 --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert.csproj @@ -0,0 +1,5 @@ + + + + + diff --git a/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/TracerProviderBuilderExtensions.cs new file mode 100644 index 0000000..7fd1f48 --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert/TracerProviderBuilderExtensions.cs @@ -0,0 +1,18 @@ +using OpenTelemetry.Trace; +namespace OpenTelemetry.Instrumentation.PhenX.EntityFrameworkCore.BulkInsert; + +/// +/// Extension methods for to add instrumentation for PhenX.EntityFrameworkCore.BulkInsert. +/// +public static class TracerProviderBuilderExtensions +{ + /// + /// Adds instrumentation for PhenX.EntityFrameworkCore.BulkInsert to the OpenTelemetry TracerProviderBuilder. + /// + /// The TracerProviderBuilder to add the instrumentation to. + /// The TracerProviderBuilder with the PhenX.EntityFrameworkCore.BulkInsert instrumentation added. + public static TracerProviderBuilder AddPhenXEntityFrameworkCoreBulkInsertInstrumentation(this TracerProviderBuilder builder) + { + return builder.AddSource("PhenX.EntityFrameworkCore.BulkInsert"); + } +}