-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ConfigureDataSource() under UseNpgsql() #2542
Comments
Some design thoughts:
|
Blocked on dotnet/efcore#29489. |
Discussion with EF team: we could count the number of NpgsqlDataSources instantiated via the NpgsqlDataSourceBuilder overload, and warn/throw when that crosses a certain threshold. This is similar to the service provider error EF itself has. This works well, until we get to using NpgsqlDataSourceBuilder internally even for the regular, connection-string UseNpgsql (this is something we want to do since it allows us to configure type mapping plugins properly). To make this work, we'd need to internally track all the NpgsqlDataSources we've instantiated, keyed by their connection string (this effectively redoes Npgsql's internal pool manager (conceptually a dictionary of connection strings to pools/data sources) outside of Npgsql. It would also not support varying type mapping plugins on the same connection strings (it would be hard to even throw when such a config discrepancy is done). So it may be better to leave the connection string UseNpgsql alone, requiring users to continue doing global type mapping as today (that would also mean un-obsoleting GlobalTypeMapper). But the recommended way would be via NpgsqlDataSourceBuilder. /cc @ajcvickers |
Regardless of the decision here... I wonder if an analyzer would be appropriate in order to steer users away from constructing the datasource/builder inside of the |
@pinkfloydx33 that's not a bad idea - opened #2588 to track that. |
worth noting that all the efcore AddDbContextWhatever methods have an overload where the configure delegate is permitted to take an builder.Services.AddDbContext<ApplicationDbContext>((provider, options) =>
options.UseNpgsql(provider.GetRequiredService<NpgsqlDataSource>(), o => { })); which is easily usable alongside |
Possibly related: I found that replacing: string? connectionString = builder.Configuration.GetConnectionString("Default");
builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql(connectionString)); with: string? connectionString = builder.Configuration.GetConnectionString("Default");
builder.Services.AddNpgsqlDataSource(connectionString);
builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql()); works in a regular application. But not in our Xunit integration tests (thousands) that run in parallel. Running a single test succeeds. But when running them all, about 45% of them fail with errors like:
and:
All tests share a single docker postgres server instance, but each test uses |
@bkoelman this shouldn't be the case... using NpgsqlDataSource with may cause EF to complain that too many (internal) service providers are being created in the tests, since different NpgsqlDataSources (currently) require different service providers (this is different from using connection strings directly, and it may change in the future). However, just using different data sources should trigger errors such as the above. For the "database seems to have just been dropped or renamed", that looks like a simple case of trying to use the same PG database concurrently from multiple tests - you'll need to check how you manage your database names etc. As to how you're ending up with a connection string lacking a password (second error), that also is likely related to your specific test setup. If you can't figure it out, try putting together some sort of minimal code repro and I'll try to help. |
I’m not entirely sure about this idea, but I think it might work. Sorry my English isn’t as good as I’d like it to be. Di Ef core Context Init:
Logic in NpgsqlDbContextOptionsBuilderExtensions:
Possible NodaTime or etc Extensions logic:
|
Discussed this with @NinoFloris recently, the API proposed here is: UseNpgsql("<connection string>", o => o
.MapEnum<Foo>() // This is EF config on NpgsqlDbContextOptionsBuilder
.DataSourceBuilder
.EnableDynamicJson()
.UseClientCertificate(...)); In other words, we'd add an NpgsqlDataSourceBuilder property on NpgsqlDbContextOptionsBuilder, which the user can use to configure all non-EF Npgsql things. Note that in the above code, MapEnum is an EFCore.PG API (introduced in #3167); since EF has access here to the NpgsqlDataSourceBuilder, this EF MapEnum can cause MapEnum on the lower-level NpgsqlDataSourceBuilder to be called as well, allowing the user to configure the enum at both EFCore.PG and Npgsql levels. One issue with this model, is that EF relies on being able to compare context options as a way to decide whether a new internal service provider is needed ("singleton options"). This works well with ints and strings, but an NpgsqlDataSourceBuilder property cannot be compared, and therefore this API is incompatible with differing NpgsqlDataSourceBuilder configurations (in the DbContext's OnConfiguring). The API is safe in "factory-style" configuration (which is what happens e.g. with DI), and is also safe in OnConfiguring as long as the NpgsqlDataSourceBuilder config doesn't change. I think it's reasonable to introduce this with a documentation warning, and to work on the EF side to allow us to detect that UseNpgsql() is being called from OnConfiguring, triggering a warning. |
Implemented this via #3277, but going with a method+lambda approach: UseNpgsql("<connection string>", o => o
.MapEnum<Foo>() // This is EF config on NpgsqlDbContextOptionsBuilder
.ConfigureDataSource(b => b
.EnableDynamicJson()
.UseClientCertificate(...))); (this allows for easily using statements when configuring the data source etc.) |
#2400 added a UseNpgsql overload which accepts a built DbDataSource, but that requires users to do the building outside the EF call, get a data source, and pass that in. This isn't a great experience.
Experiment with having a UseNpgsql overload which accepts an NpgsqlDataSourceBuilder lambda, allowing configuring the data source in-place. The potential problem is the Intellisense ambiguity with the overload accepting a DbContextOptionsBuilder lambda.
Another advantage of a NpgsqlDataSourceBuilder lambda is that EF plugins (NodaTime, NTS) would be able to apply ADO-level mapping plugins to the data source builder before the data source is built, at least in theory. That would provide a seamless experience where you just add NTS at the EF level, and don't have to worry about the ADO.NET/data source level.
The text was updated successfully, but these errors were encountered: