9.0 Release Notes
Npgsql.EntityFrameworkCore.PostgreSQL version 9.0 is out and available on nuget.org.
Improved, unified configuration experience
The Npgsql EF provider is built on top of the lower-level Npgsql ADO.NET provider; the configuration interface between these two layers was less than ideal, and configuration been more difficult than it should have been. For version 9.0, the configuration experience has been considerably improved.
Since version 7, the Npgsql ADO.NET provider has been moving to NpgsqlDataSource as the preferred way of configuring connections and obtaining them. At the EF level, it has been possible to pass an NpgsqlDataSource instance to UseNpgsql()
; but this required that the user separately configure a data source and manage it. In addition, features such as plugins and enums require support from both the EF and ADO.NET layers, forcing users to perform multiple setup actions at the different layers.
With version 9, UseNpgsql()
becomes a single point for configuration, for both the EF and ADO.NET levels. EF can now internally set up an NpgsqlDataSource, automatically applying all the necessary configuration to it, and also exposes an API to allow users to apply arbitrary configuration to it as well:
builder.Services.AddDbContextPool<BloggingContext>(opt =>
opt.UseNpgsql(
builder.Configuration.GetConnectionString("BloggingContext"),
o => o
.SetPostgresVersion(13, 0)
.UseNodaTime()
.MapEnum<Mood>("mood")
.ConfigureDataSource(dataSourceBuilder => dataSourceBuilder.UseClientCertificate(certificate))));
In the above code, the following configuration gestures are performed:
SetPostgresVersion()
is an EF-only option to produce SQL for PostgreSQL version 13 (avoiding newer incompatible features)UseNodaTime()
, adds a plugin allowing use of NodaTime for date/time type mapping. This also requires an ADO.NET NodaTime plugin which needed to be configured separately, but this is now done automatically.MapEnum()
maps a .NET enum type. LikeUseNodaTime()
, this also used to require a separate ADO.NET configuration gesture, but is now done automatically. As an added bonus, doing this now also adds the enum to the model, causing the enum to be created in the database via EF's migrations.ConfigureDataSource()
exposes an NpgsqlDataSourceBuilder, which you can use to configure arbitrary ADO.NET options. In this example, the certificate is defined for the TLS authentication process.
For more information, see the getting started docs.
Improved configuration for enums and plugins
Previously, configuration around enums and plugins (NodaTime, NetTopologySuite) was complicated, requiring multiple setup actions at both the EF and the lower-level Npgsql layers. EF 9.0 improves the configuration story, allowing you to configure enums and plugins via a single EF gesture:
builder.Services.AddPooledDbContext<MyContext>(options => options.UseNpgsql(
"<connection string>",
o => o.MapEnum<Mood>("mood")));
This takes care of everything - EF configuration, lower-level Npgsql configuration and even the addition of the enum to the EF model, which ensures that the enum is created in the database in EF migrations.
See the enum, NodaTime and NetTopologySuite documentation for more details.
UUIDv7 GUIDs are generated by default
When your entity types have a Guid
key, EF Core by default generates key values for new entities client-side - in .NET - before inserting those entity types to the database; this can be better for performance in some situations. Before version 9.0, the provider generated random GUIDs (version 4) by calling the .NET Guid.NewGuid()
function. Unfortunately, random GUIDs aren't ideal for database indexing and can cause performance issues.
Version 9.0 of the provider now generates the recently standardized version 7 GUIDs, which is a sequential GUID type that's more appropriate for database indexes and improves their performance. This new behavior is on by default and takes effect simply by upgrading the provider version.
See this post for more details and performance numbers on random vs. sequential GUIDs.
Thanks to @ChrisJollyAU and @Timovzl for contributing this improvement!
Other new features
- Translate
array.Where(i => i != x)
toarray_remove(array, x)
- Translate
DateOnly.DayNumber
,DateOnly.FromDayNumber()
and simplifydateOnly1.DayNumber - dateOnly2.DayNumber
todateOnly1 - dateOnly2
. - Map the PostgreSQL
jsonpath
type to .NET string; this allows mapping tojsonpath
columns.
See the 9.0.0 milestone for the full list of Npgsql EF provider issues.
Breaking changes
Enum mappings must now be configured at the EF level
Previously, enum configuration involved mapping the enum at the lower-level Npgsql layer (either via NpgsqlDataSourceBuilder.MapEnum
or via NpgsqlConnection.GlobalTypeMapper.MapEnum
); the EF provider automatically picked this configuration up for the EF-level setup. Unfortunately, this design created numerous issues and bugs.
As part of the improved enum configuration story in version 9.0 (see above), enums must now be configured at the EF level; although this is a breaking change for existing applications, it usually results in simplified setup code and fixes various bugs and problematic behavior.
If your application calls UseNpgsql
with a simple connection string (rather than an NpgsqlDataSource), it simply needs to add a MapEnum
call there:
builder.Services.AddDbContext<MyContext>(options => options.UseNpgsql(
"<connection string>",
o => o.MapEnum<Mood>("mood")));
All other setup code - the MapEnum
call on NpgsqlConnection.GlobalTypeMapper
and the HasPostgresEnum
call in OnModelCreating
- can be removed.
If your application passes an NpgsqlDataSource to UseNpgsql
, it also needs to add the MapEnum
call as above; but the MapEnum
call on NpgsqlDataSourceBuilder
must also be kept.
See the enum documentation for more information.
Contributors
A big thank you to all the following people who contributed to the 9.0 release!
Milestone 9.0.0
Contributor | Assigned issues |
---|---|
@roji | 34 |
@ChrisJollyAU | 1 |
@Timovzl | 1 |