diff --git a/src/EFCore.PG/Infrastructure/Internal/INpgsqlSingletonOptions.cs b/src/EFCore.PG/Infrastructure/Internal/INpgsqlSingletonOptions.cs
index 0eb58b004..259a278f1 100644
--- a/src/EFCore.PG/Infrastructure/Internal/INpgsqlSingletonOptions.cs
+++ b/src/EFCore.PG/Infrastructure/Internal/INpgsqlSingletonOptions.cs
@@ -1,32 +1,39 @@
-namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
+using System.Data.Common;
+
+namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
///
-/// Represents options for Npgsql that can only be set at the singleton level.
+/// Represents options for Npgsql that can only be set at the singleton level.
///
public interface INpgsqlSingletonOptions : ISingletonOptions
{
///
- /// The backend version to target.
+ /// The backend version to target.
///
Version PostgresVersion { get; }
///
- /// The backend version to target, but returns unless the user explicitly specified a version.
+ /// The backend version to target, but returns unless the user explicitly specified a version.
///
Version? PostgresVersionWithoutDefault { get; }
///
- /// Whether to target Redshift.
+ /// Whether to target Redshift.
///
bool UseRedshift { get; }
///
- /// True if reverse null ordering is enabled; otherwise, false.
+ /// Whether reverse null ordering is enabled.
///
bool ReverseNullOrderingEnabled { get; }
///
- /// The collection of range mappings.
+ /// The data source being used, or if a connection string or connection was provided directly.
+ ///
+ DbDataSource? DataSource { get; }
+
+ ///
+ /// The collection of range mappings.
///
IReadOnlyList UserRangeDefinitions { get; }
}
\ No newline at end of file
diff --git a/src/EFCore.PG/Internal/NpgsqlSingletonOptions.cs b/src/EFCore.PG/Internal/NpgsqlSingletonOptions.cs
index 7216414e7..80077e628 100644
--- a/src/EFCore.PG/Internal/NpgsqlSingletonOptions.cs
+++ b/src/EFCore.PG/Internal/NpgsqlSingletonOptions.cs
@@ -1,4 +1,5 @@
-using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
+using System.Data.Common;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Internal;
@@ -46,6 +47,14 @@ public class NpgsqlSingletonOptions : INpgsqlSingletonOptions
///
public virtual bool ReverseNullOrderingEnabled { get; private set; }
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual DbDataSource? DataSource { get; private set; }
+
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -72,6 +81,7 @@ public virtual void Initialize(IDbContextOptions options)
PostgresVersion = npgsqlOptions.PostgresVersion ?? DefaultPostgresVersion;
UseRedshift = npgsqlOptions.UseRedshift;
ReverseNullOrderingEnabled = npgsqlOptions.ReverseNullOrdering;
+ DataSource = npgsqlOptions.DataSource;
UserRangeDefinitions = npgsqlOptions.UserRangeDefinitions;
}
@@ -104,6 +114,12 @@ public virtual void Validate(IDbContextOptions options)
nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
}
+ if (!ReferenceEquals(DataSource, npgsqlOptions.DataSource))
+ {
+ throw new InvalidOperationException(
+ NpgsqlStrings.TwoDataSourcesInSameServiceProvider(nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
+ }
+
if (UserRangeDefinitions.Count != npgsqlOptions.UserRangeDefinitions.Count
|| UserRangeDefinitions.Zip(npgsqlOptions.UserRangeDefinitions).Any(t => t.First != t.Second))
{
diff --git a/src/EFCore.PG/Properties/NpgsqlStrings.Designer.cs b/src/EFCore.PG/Properties/NpgsqlStrings.Designer.cs
index 3c2b2f439..3bcd31e53 100644
--- a/src/EFCore.PG/Properties/NpgsqlStrings.Designer.cs
+++ b/src/EFCore.PG/Properties/NpgsqlStrings.Designer.cs
@@ -19,6 +19,14 @@ public static class NpgsqlStrings
private static readonly ResourceManager _resourceManager
= new ResourceManager("Npgsql.EntityFrameworkCore.PostgreSQL.Properties.NpgsqlStrings", typeof(NpgsqlStrings).Assembly);
+ ///
+ /// Using two distinct data sources within a service provider is not supported, and Entity Framework is not building its own internal service provider. Either allow Entity Framework to build the service provider by removing the call to '{useInternalServiceProvider}', or ensure that the same data source is used for all uses of a given service provider passed to '{useInternalServiceProvider}'.
+ ///
+ public static string TwoDataSourcesInSameServiceProvider(object? useInternalServiceProvider)
+ => string.Format(
+ GetString("TwoDataSourcesInSameServiceProvider", nameof(useInternalServiceProvider)),
+ useInternalServiceProvider);
+
///
/// '{entityType1}.{property1}' and '{entityType2}.{property2}' are both mapped to column '{columnName}' in '{table}', but are configured with different compression methods.
///
diff --git a/src/EFCore.PG/Properties/NpgsqlStrings.resx b/src/EFCore.PG/Properties/NpgsqlStrings.resx
index 22cada8de..1759bc4a9 100644
--- a/src/EFCore.PG/Properties/NpgsqlStrings.resx
+++ b/src/EFCore.PG/Properties/NpgsqlStrings.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Using two distinct data sources within a service provider is not supported, and Entity Framework is not building its own internal service provider. Either allow Entity Framework to build the service provider by removing the call to '{useInternalServiceProvider}', or ensure that the same data source is used for all uses of a given service provider passed to '{useInternalServiceProvider}'.
+
'{entityType1}.{property1}' and '{entityType2}.{property2}' are both mapped to column '{columnName}' in '{table}' but are configured with different compression methods.
diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
index dce4ce40f..1d899cff1 100644
--- a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
+++ b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
@@ -68,8 +68,6 @@ static NpgsqlTypeMappingSource()
///
private readonly Dictionary> _multirangeTypeMappings;
- private static MethodInfo? _adoUserTypeMappingsGetMethodInfo;
-
private readonly bool _supportsMultiranges;
#region Mappings
@@ -207,7 +205,8 @@ static NpgsqlTypeMappingSource()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public NpgsqlTypeMappingSource(TypeMappingSourceDependencies dependencies,
+ public NpgsqlTypeMappingSource(
+ TypeMappingSourceDependencies dependencies,
RelationalTypeMappingSourceDependencies relationalDependencies,
ISqlGenerationHelper sqlGenerationHelper,
INpgsqlSingletonOptions npgsqlSingletonOptions)
@@ -443,7 +442,7 @@ public NpgsqlTypeMappingSource(TypeMappingSourceDependencies dependencies,
StoreTypeMappings = new ConcurrentDictionary(storeTypeMappings, StringComparer.OrdinalIgnoreCase);
ClrTypeMappings = new ConcurrentDictionary(clrTypeMappings);
- LoadUserDefinedTypeMappings(sqlGenerationHelper);
+ LoadUserDefinedTypeMappings(sqlGenerationHelper, npgsqlSingletonOptions.DataSource as NpgsqlDataSource);
_userRangeDefinitions = npgsqlSingletonOptions?.UserRangeDefinitions ?? Array.Empty();
}
@@ -452,28 +451,38 @@ public NpgsqlTypeMappingSource(TypeMappingSourceDependencies dependencies,
/// To be used in case user-defined mappings are added late, after this TypeMappingSource has already been initialized.
/// This is basically only for test usage.
///
- public virtual void LoadUserDefinedTypeMappings(ISqlGenerationHelper sqlGenerationHelper)
- => SetupEnumMappings(sqlGenerationHelper);
+ public virtual void LoadUserDefinedTypeMappings(
+ ISqlGenerationHelper sqlGenerationHelper,
+ NpgsqlDataSource? dataSource)
+ => SetupEnumMappings(sqlGenerationHelper, dataSource);
///
/// Gets all global enum mappings from the ADO.NET layer and creates mappings for them
///
- protected virtual void SetupEnumMappings(ISqlGenerationHelper sqlGenerationHelper)
+ protected virtual void SetupEnumMappings(ISqlGenerationHelper sqlGenerationHelper, NpgsqlDataSource? dataSource)
{
+ var adoEnumMappings = new List();
+
#pragma warning disable CS0618 // NpgsqlConnection.GlobalTypeMapper is obsolete
- _adoUserTypeMappingsGetMethodInfo ??= NpgsqlConnection.GlobalTypeMapper.GetType().GetProperty("UserTypeMappings")?.GetMethod;
+ if (NpgsqlConnection.GlobalTypeMapper.GetType().GetProperty("UserTypeMappings")?.GetMethod is { } globalTypeMappingsMethodInfo
+ && globalTypeMappingsMethodInfo.Invoke(NpgsqlConnection.GlobalTypeMapper, Array.Empty