npgsql / efcore.pg

Entity Framework Core provider for PostgreSQL
PostgreSQL License
1.52k stars 223 forks source link

Support for mapping JsonNode properties like JsonDocument #3021

Open LaXiS96 opened 9 months ago

LaXiS96 commented 9 months ago

JsonDocument properties in entity models are automatically mapped to jsonb columns, while JsonNodes are not: can this behavior be implemented? I see that Npgsql itself can handle this with EnableDynamicJson, but it's not clear to me if the EFCore provider supports this.

My use case is needing mutable dynamic JSON objects to read and write. System.Text.Json does not seem to have any sensible way to convert between JsonDocument and JsonNode, which is a huge missing feature in my opinion (I really liked Newtonsoft's JToken, even if slightly less performant).

I cannot use EFCore's ToJson since my objects' structure is not known at compile time, but they are guaranteed to be deserializable to a Dictionary<string, object?> or JsonObject for that matter. The application I am working on has been storing dynamic JSON objects in text columns on SQL Server since EFCore 2 (with all the related issues; consider EFCore 8 still doesn't support this), and I am considering migrating to PostgreSQL for JSON-related performance issues.

roji commented 9 months ago

Support for weakly-typed JSON mapping on the EF side (both JsonDocument and JsonNode) is tracked by #28871. I likely won't continue working on weakly-typed JSON support specifically in this provider (i.e. by adding JsonNode support here), the better way forward is for it all to get implemented upstream in EF itself.

BTW it really should be quite trivial to go from a mutable JsonNode tree to a JsonDocument, i.e. by serializing the mutable tree to a string and then building a JsonDocument over that. Given how JsonDocument actually works, there's very little chance that any other approach would be possible anyway (JsonDocument is a highly-optimized parser over JSON data string, it probably isn't possible to make it somehow work "over" a JsonNode tree without compromising perf in a significant way).

So my recommendation would be to just do that for now.

LaXiS96 commented 9 months ago

Thank you @roji, I totally understand leaving this behavior to be handled upstream, and have already upvoted dotnet/efcore#28871

However, I do not consider sensible deserializing the column to JsonDocument, serializing it back to JSON and finally deserializing it again to JsonNode to mutate it 😆 it clearly is much more wasteful than either deserializing directly to JsonNode or Newtonsoft's JToken. I commend STJ's focus on performance, but I feel usability is impacted in many scenarios.