diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs b/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
index 3788670e0..87bce1171 100644
--- a/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
+++ b/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
@@ -17,6 +17,9 @@ public class NpgsqlRelationalConnection : RelationalConnection, INpgsqlRelationa
private readonly ProvideClientCertificatesCallback? _provideClientCertificatesCallback;
private readonly RemoteCertificateValidationCallback? _remoteCertificateValidationCallback;
+ // True when a connection was supplied after construction, e.g. via Database.SetDbConnection(). It isn't reflected in the options.
+ private bool _isDbConnectionSet;
+
#pragma warning disable CS0618 // ProvidePasswordCallback is obsolete
private readonly ProvidePasswordCallback? _providePasswordCallback;
#pragma warning restore CS0618
@@ -147,6 +150,19 @@ public override string? ConnectionString
}
}
+ ///
+ /// 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 override void SetDbConnection(DbConnection? value, bool contextOwnsConnection)
+ {
+ base.SetDbConnection(value, contextOwnsConnection);
+
+ _isDbConnectionSet = value is not null;
+ }
+
///
/// 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
@@ -205,7 +221,7 @@ public virtual INpgsqlRelationalConnection CreateAdminConnection()
// Cloned connections must be owned so disposing the wrapper also closes and disposes them.
var adminNpgsqlOptions = DataSource is not null
? npgsqlOptions.WithConnection(((NpgsqlConnection)CreateDbConnection()).CloneWith(adminConnectionString), owned: true)
- : npgsqlOptions.Connection is not null
+ : npgsqlOptions.Connection is not null || _isDbConnectionSet
? npgsqlOptions.WithConnection(DbConnection.CloneWith(adminConnectionString), owned: true)
: npgsqlOptions.WithConnectionString(adminConnectionString);
diff --git a/test/EFCore.PG.FunctionalTests/ConnectionSpecificationTest.cs b/test/EFCore.PG.FunctionalTests/ConnectionSpecificationTest.cs
index c16a173f0..6a96209e7 100644
--- a/test/EFCore.PG.FunctionalTests/ConnectionSpecificationTest.cs
+++ b/test/EFCore.PG.FunctionalTests/ConnectionSpecificationTest.cs
@@ -278,6 +278,33 @@ public async Task Can_create_admin_connection_with_connection()
adminConnection.Open();
}
+ [Fact]
+ public async Task Can_create_admin_connection_with_connection_set_via_SetDbConnection()
+ {
+ await using var _ = await NpgsqlTestStore.GetNorthwindStoreAsync();
+
+ // Once opened, Npgsql removes the password from the connection's ConnectionString (Persist Security Info=false), so the admin
+ // connection must be cloned from the connection rather than rebuilt from its connection string.
+ await using var connection = new NpgsqlConnection(NpgsqlTestStore.NorthwindConnectionString);
+ await connection.OpenAsync();
+
+ var optionsBuilder = new DbContextOptionsBuilder();
+ optionsBuilder.UseNpgsql(b => b.ApplyConfiguration());
+ await using var context = new GeneralOptionsContext(optionsBuilder.Options);
+ context.Database.SetDbConnection(connection);
+
+ var relationalConnection = context.GetService();
+ await using (var adminConnection = relationalConnection.CreateAdminConnection())
+ {
+ Assert.Equal("postgres", new NpgsqlConnectionStringBuilder(adminConnection.ConnectionString).Database);
+
+ await adminConnection.OpenAsync(CancellationToken.None);
+ }
+
+ // Disposing the admin connection must not dispose the connection supplied by the user
+ Assert.Equal(System.Data.ConnectionState.Open, connection.State);
+ }
+
private class GeneralOptionsContext(DbContextOptions options) : NorthwindContextBase(options);
#endregion