Skip to content
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

Major work around DbDataSource management, enum handling and plugins #3167

Merged
merged 3 commits into from
May 18, 2024

Conversation

roji
Copy link
Member

@roji roji commented May 12, 2024

  • Added user-facing enum mapping API on NpgsqlDbContextOptionsBuilder, and removed hacky reflection-based pulling of enum type mappings from the Npgsql ADO.NET layer. This is #3063.
  • Thanks to the above, NpgsqlTypeMappingSource (a singleton service) no longer needs the NpgsqlDataSource (to pull enum mappings from). Changed DbDataSource to be scoped (when configured explicitly by the user via UseNpgsql()), allowing it to change across invocations. This fixes #2891, #3086.
  • When the new EF MapEnum() API is used, we now create a data source internally, configuring it with the enum definition as well, so users no longer need to configure both EF and ADO.NET for the enum. This is #1026.
    • The internally created data source is (obviously) a singleton, and if the user passes different connection strings to UseNpgsql(), we throw we create new data sources, cached by the connection string. This means it's no longer possible to do both enums and switch connection strings (breaking change).
  • Similarly to enums, added infrastructure to allow EF plugins to participate in the NpgsqlDataSourceBuilder configuration. This is used by the NTS and NodaTime plugins to add the corresponding ADO.NET-level plugins.
  • Removed all enum- and plugin-related global configuration in the tests, switching to the above new data source APIs.
    • Now that the plugins just configure the internal data source and the obsolete global type mapper is no longer used, merged the NodaTime test project into the general test project (NodaTime previously had its own project to avoid interference via the global type mapper).
  • Added a convention to add enums to the model based on the new, explicit user API above. This means that the single EF MapEnum() in UseNpgsql() is now sufficient to configure EF's type mapping, the ADO.NET type mapping, and cause the enum to be created in the database. This completes #1026.

Future task: add NpgsqlDataSourceBuilder to NpgsqlDbContextOptionsBuilder, to allow easy configuration of Npgsql via the EF API (#2542). Accessing the DataSourceBuilder would also count as "requires internal data source", just like enums/plugins.

Fixes #2891
Fixes #3063
Fixes #1026

See comments below for last remaining tasks.

/cc @NinoFloris @ajcvickers

@roji roji force-pushed the ScopedDataSource branch 2 times, most recently from d8db176 to d4ae264 Compare May 13, 2024 13:13
Fixes npgsql#2891
Fixes npgsql#3063
Fixes npgsql#1026

Co-authored-by: Nino Floris <mail@ninofloris.com>
Copy link
Member

@NinoFloris NinoFloris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a great upgrade! My comments mostly consist of nits and questions.


// If the user hasn't configured anything in UseNpgsql (no data source, no connection, no connection string), check the
// application service provider to see if a data source is registered there, and return that.
{ ConnectionString: null } when applicationServiceProvider?.GetService<NpgsqlDataSource>() is DbDataSource dataSource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up to this approach could be the user providing a serviceKey to some new option on UseNpgsql.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea, can absolutely see that happening.

src/EFCore.PG/Storage/Internal/NpgsqlDataSourceManager.cs Outdated Show resolved Hide resolved
_sqlGenerationHelper.DelimitIdentifier(name, schema),
schema is null ? name : schema + "." + name,
enumDefinition.ClrType,
enumDefinition.Labels);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the conclusion around whether to sort these alphabetically?

Copy link
Member Author

@roji roji May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is done in the convention which "copies" the definitions from the context options to the model (code), because that's the part that ends up forming the migration. In the type mapping source I don't think there should be any significance to the ordering, we only use the labels when we need to stick a label constant in the SQL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also adding sorting in NpgsqlMigrationsSqlGenerator, when detecting new labels (this is an improvement regardless of the other changes in this PR).

}
else
{
// TODO: Not sure what to do about quoting. Is the user expected to configure properties
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think the current code as-is is good enough for merging for the moment (e.g. until we do npgsql/npgsql#5710)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah as long as users can pass quoted names - as I understand they can - they should always be able to make EF map things correctly when mappingInfo.StoreTypeName is quoted.

@roji roji force-pushed the ScopedDataSource branch from d4ae264 to 79f8abe Compare May 17, 2024 18:19
@roji roji marked this pull request as ready for review May 17, 2024 18:19
@roji
Copy link
Member Author

roji commented May 17, 2024

@NinoFloris can I get another quick review from you on the added changes etc.? Especially on the new logic adding the ConcurrentDictionary for multiple data sources in NpgsqlDataSourceManager, and the concurrency handling around that?

throw new InvalidOperationException(NpgsqlStrings.DataSourceWithMultipleConnectionStrings(dataSourceFeature));
newDataSource.Dispose();
}
else if (_isDisposed == 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the infra looks like - in terms of full disposal blocking this method from being called later on - but you might want this check to be done before as well. Just so you don't keep adding more items to the dictionary when things are already disposed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the infra looks like

Me neither... My logic here is that it's OK if a data source gets added to the dictionary during/after Dispose (after all Dispose doesn't clear the dictionary, we don't really care) - the important bit is that the data sources always get disposed, which I think this achieves...

Will go ahead and merge, we can always revisit if needed (unlikely).

Copy link
Member

@NinoFloris NinoFloris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@roji roji merged commit 6b3ca68 into npgsql:main May 18, 2024
15 checks passed
@roji roji deleted the ScopedDataSource branch May 18, 2024 17:42
roji added a commit to roji/Npgsql that referenced this pull request May 18, 2024
Following npgsql/efcore.pg#3167, which
removes EF's logic for extracting enum mappings from Npgsql.
NinoFloris pushed a commit to roji/Npgsql that referenced this pull request May 30, 2024
Following npgsql/efcore.pg#3167, which
removes EF's logic for extracting enum mappings from Npgsql.
roji added a commit to npgsql/npgsql that referenced this pull request May 30, 2024
Following npgsql/efcore.pg#3167, which
removes EF's logic for extracting enum mappings from Npgsql.
@roji roji linked an issue Jun 27, 2024 that may be closed by this pull request
@ciolial

This comment was marked as resolved.

@roji

This comment was marked as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants