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

Document new out-of-order jsonb polymorphism support #380

Merged
merged 2 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions conceptual/Npgsql/release-notes/9.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ See the [tracing documentation](/doc/diagnostics/tracing.html) for more informat

## Mapping improvements

### Support System.Text.Json polymorphism with PostgreSQL `jsonb`

> [!NOTE]
> If you're using EF Core, the below pertains to the EF provider's [legacy POCO mapping](https://www.npgsql.org/efcore/mapping/json.html?tabs=data-annotations%2Cjsondocument#legacy-poco-mapping-deprecated), and not to the recommended [ToJson mapping](https://www.npgsql.org/efcore/mapping/json.html?tabs=data-annotations%2Cjsondocument#poco-mapping). Unfortunately, the latter does not yet support polymorphic serialization (support for this may be added in EF 10).

System.Text.Json has supported [polymorphic serialization](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism) for a while, using a JSON `$type` property as the type discriminator. However, it was required that the `$type` property be at the top of the JSON document; this causes problems serializing to the PostgreSQL `jsonb` type, since that type does **not** preserve property order in JSON objects.

System.Text.Json 9.0 brings support for [out-of-order metadata reads](https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-9/#out-of-order-metadata-reads), which is an opt-in feature allowing the `$type` property to be anywhere in the JSON object. When using Npgsql, you can opt into this when configuring your <xref:Npgsql.NpgsqlDataSourceBuilder> as follows:

```c#
var builder = new NpgsqlDataSourceBuilder("<connection string>");
builder
.EnableDynamicJson()
.ConfigureJsonOptions(new JsonSerializerOptions { AllowOutOfOrderMetadataProperties = true });
await using var dataSource = builder.Build();
```

Once that's done, you can use JSON polymorphism with `jsonb`. If you're still targeting .NET 8.0, you can take a reference on System.Text.Json 9.0 in order to use `AllowOutOfOrderMetadataProperties`.

### Add support for cidr <-> IPNetwork mapping

.NET 8 added a new type [IPNetwork](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipnetwork?view=net-8.0) which represents an IP network with an [IPAddress](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress?view=net-8.0) containing the network prefix and an `int` defining the prefix length. This type seems to be a perfect fit for PostgreSQL's `cidr` type, which is why we added support to read and write it. The default when reading a `cidr` is still `NpgsqlCidr` in 9.0, though this will likely change in Npgsql 10.0. See [this issue](https://github.com/npgsql/npgsql/issues/5821) for more info.
Expand Down
18 changes: 18 additions & 0 deletions conceptual/Npgsql/types/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ class MyPoco

This mapping method is quite powerful, allowing you to read and write nested graphs of objects and arrays to PostgreSQL without having to deal with serialization yourself.

### Polymorphic JSON mapping

Npgsql uses System.Text.Json to perform the actual serialization and deserialization of your POCO types to JSON. System.Text.Json support [`polymorphioc serialization`](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism), which allows serializing type hierarchies, using a JSON `$type` property as the type discriminator.

If you're using the `json` type, you can use System.Text.Json's polymorphic serialization without any extra steps. However, if you're using `jsonb` (which is generally recommended), then you'll run into trouble: System.Text.Json requires that the `$type` property be at the top of the JSON document, but `jsonb` does **not** preserve property order in JSON objects.

System.Text.Json 9.0 brings support for [out-of-order metadata reads](https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-9/#out-of-order-metadata-reads), which is an opt-in feature allowing the `$type` property to be anywhere in the JSON object. When using Npgsql, you can opt into this when configuring your <xref:Npgsql.NpgsqlDataSourceBuilder> as follows:

```c#
var builder = new NpgsqlDataSourceBuilder("<connection string>");
builder
.EnableDynamicJson()
.ConfigureJsonOptions(new JsonSerializerOptions { AllowOutOfOrderMetadataProperties = true });
await using var dataSource = builder.Build();
```

Once that's done, you can use JSON polymorphism with `jsonb`. If you're still targeting .NET 8.0, you can take a reference on System.Text.Json 9.0 in order to use `AllowOutOfOrderMetadataProperties`.

## System.Text.Json DOM types

There are cases in which mapping JSON data to POCOs isn't appropriate; for example, your JSON column may not contain a fixed schema and must be inspected to see what it contains; for these cases, Npgsql supports mapping JSON data to [JsonDocument](https://docs.microsoft.com/dotnet/api/system.text.json.jsondocument) or [JsonElement](https://docs.microsoft.com/dotnet/api/system.text.json.jsonelement) ([see docs](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/use-dom#use-jsondocument)):
Expand Down