Skip to content

Commit

Permalink
Document new out-of-order jsonb polymorphism support (#380)
Browse files Browse the repository at this point in the history
  • Loading branch information
roji authored Nov 19, 2024
1 parent f388cd0 commit b40049b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
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

0 comments on commit b40049b

Please sign in to comment.