Skip to content

Commit a64c405

Browse files
authored
Allow null connection string with ConfigureDataSource (#3693)
Fixes #3692
1 parent f4c1183 commit a64c405

File tree

3 files changed

+34
-15
lines changed

3 files changed

+34
-15
lines changed

src/EFCore.PG/Storage/Internal/NpgsqlDataSourceManager.cs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,37 @@ public NpgsqlDataSourceManager(IEnumerable<INpgsqlDataSourceConfigurationPlugin>
6565
// must be manually set up by the user for the enum, of course).
6666
{ Connection: not null } => null,
6767

68-
// If the user hasn't configured anything in UseNpgsql (no data source, no connection, no connection string), check the
69-
// application service provider to see if a data source is registered there, and return that.
70-
{ ConnectionString: null } when applicationServiceProvider?.GetService<NpgsqlDataSource>() is DbDataSource dataSource
71-
=> dataSource,
72-
73-
// Otherwise if there's no connection string, abort: a connection string is required to create a data source in any case.
74-
{ ConnectionString: null } or null => null,
68+
// If a data source builder action is specified, always create a data source.
69+
{ DataSourceBuilderAction: not null } o => GetSingletonDataSource(o),
70+
71+
// If the user hasn't configured anything in UseNpgsql (no data source, no data source builder action, no connection,
72+
// no connection string), check the application service provider to see if a data source is registered there, and return that.
73+
// Otherwise if there's no connection string, abort: either a connection string or DataSourceBuilderAction is required
74+
// to create a data source in any case.
75+
{ ConnectionString: null } or null
76+
=> applicationServiceProvider?.GetService<NpgsqlDataSource>() is DbDataSource dataSource
77+
? dataSource
78+
: null,
7579

7680
// The following are features which require an NpgsqlDataSource, since they require configuration on NpgsqlDataSourceBuilder.
77-
{ DataSourceBuilderAction: not null } => GetSingletonDataSource(npgsqlOptionsExtension),
78-
{ EnumDefinitions.Count: > 0 } => GetSingletonDataSource(npgsqlOptionsExtension),
79-
_ when _plugins.Any() => GetSingletonDataSource(npgsqlOptionsExtension),
81+
{ EnumDefinitions.Count: > 0 } o => GetSingletonDataSource(o),
82+
{ } o when _plugins.Any() => GetSingletonDataSource(o),
8083

8184
// If there's no configured feature which requires us to use a data source internally, don't use one; this causes
82-
// NpgsqlRelationalConnection to use the connection string as before (no data source), allowing switching connection strings
83-
// with the same service provider etc.
85+
// NpgsqlRelationalConnection to use the connection string as before (no data source at the EF level), allowing switching
86+
// connection strings with the same service provider etc.
8487
_ => null
8588
};
8689

8790
private DbDataSource GetSingletonDataSource(NpgsqlOptionsExtension npgsqlOptionsExtension)
8891
{
8992
var connectionString = npgsqlOptionsExtension.ConnectionString;
90-
Check.DebugAssert(connectionString is not null, "Connection string can't be null");
93+
94+
// It should be possible to use ConfigureDataSource() without supplying a connection string, providing the connection
95+
// information via the connection string builder on the NpgsqlDataSourceBuilder. In order to support this, we
96+
// coalesce null connection strings to empty strings (since dictionaries don't allow null keys).
97+
// This is in line with general ADO.NET practice of coalescing null connection strings to empty strings.
98+
connectionString ??= string.Empty;
9199

92100
if (_dataSources.TryGetValue(connectionString, out var dataSource))
93101
{

test/EFCore.PG.FunctionalTests/BadDataJsonDeserializationNpgsqlTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Microsoft.EntityFrameworkCore;
22

3-
public class BadDataJsonDeserializationSqlServerTest : BadDataJsonDeserializationTestBase
3+
public class BadDataJsonDeserializationNpgsqlTest : BadDataJsonDeserializationTestBase
44
{
55
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
66
=> base.OnConfiguring(optionsBuilder.UseNpgsql(b => b.UseNetTopologySuite()));

test/EFCore.PG.Tests/NpgsqlRelationalConnectionTest.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ public void Data_source_config_with_same_connection_string_and_different_lambda(
159159
Assert.Same(connection1.DbDataSource, connection2.DbDataSource);
160160
}
161161

162+
[Fact]
163+
public void Data_source_config_without_a_connection_string()
164+
{
165+
var context = new ConfigurableContext(
166+
connectionString: null,
167+
no => no.ConfigureDataSource(dsb => dsb.ConnectionStringBuilder.Host = "192.168.1.1"));
168+
var connection1 = (NpgsqlRelationalConnection)context.GetService<IRelationalConnection>();
169+
Assert.Equal("Host=192.168.1.1", connection1.ConnectionString);
170+
Assert.NotNull(connection1.DbDataSource);
171+
}
172+
162173
[Fact]
163174
public void Plugin_config_with_same_connection_string()
164175
{
@@ -439,7 +450,7 @@ public FakeDbContext(DbContextOptions<FakeDbContext> options)
439450
}
440451
}
441452

442-
private class ConfigurableContext(string connectionString, Action<NpgsqlDbContextOptionsBuilder>? npgsqlOptionsAction = null) : DbContext
453+
private class ConfigurableContext(string? connectionString, Action<NpgsqlDbContextOptionsBuilder>? npgsqlOptionsAction = null) : DbContext
443454
{
444455
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
445456
=> optionsBuilder.UseNpgsql(connectionString, npgsqlOptionsAction);

0 commit comments

Comments
 (0)