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

JSON: optimize update path for single property element - don't wrap the value in json array #30410

Closed
maumar opened this issue Mar 6, 2023 · 3 comments · Fixed by #30422
Closed
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@maumar
Copy link
Contributor

maumar commented Mar 6, 2023

Currently when updating single property inside json, we create parameter value as JSON array and put the value in it, then extract it in the update statement. This is because we want to guarantee the correct format of the value that we want to update (if we rely on database casting from a given type to string, we may end up in bad format and data gets corrupted. This only happens for some data types on sql server (guid, datetime, datetime offset) - so maybe we can special case. But need to look at Sqlite. Alternatively, if/when we have dedicated type mapping for json, we might be able to always generate parameter string value in correct format to be stored inside JSON.

@roji
Copy link
Member

roji commented Mar 6, 2023

@maumar can you provide a bit more details on the bad format corruption?

I see that in ModificationCommand, for partial updates we simply do JsonValue.Create over the property value. For any types not natively supported by JSON (DateTime, Guid), can't we just call ToJsonString() on that JsonValue and sent that string as the parameter value to JSON_MODIFY? I think that doesn't require any array, JSON_VALUE or server-side casting.

(for natively-supported JSON types - int/bool/null - we should be able to just send a regular parameter with the right value, e.g. send bool as a BIT parameter, which JSON_MODIFY applies as true/false).

@ajcvickers @AndriySvyryd this is related to our recent conversations about how to generate a literal representation of something in JSON context; here the problem is what we do with parameters. In other words, if we want to send a DateTime/Guid into a JSON document (partial update), we need to be able to actually send a string with the appropriate timestamp format. We currently delegate this conversion to System.Text.Json in ModificationCommand, but this can/should probably be refactored into the same facility we'd use for literals.

@maumar
Copy link
Contributor Author

maumar commented Mar 6, 2023

by corruption I mean that when we try to ExtractJsonProperty<T> we get an error, because the JsonElement we read can't be deserialized into the requested type. Calling ToJsonString on those params should work, especially that now we have a provider specific hook (in case we need some special processing for Sqlite etc.) - will give it a try

edit: when generating ColumnModification, we use JSON column type mapping (the only one we have available, since individual JSON properties don't have their own mappings). Even if the value is, say, int = 1234, the parameter that gets generated is nvarchar (i.e. '1234'), so we still need to keep the convert before we pass the parameter value to JSON_MODIFY. But we can get rid of the array trick at least. And the convert will likely be able to go away when/if we get dedicated JSON type mapping.

@AndriySvyryd
Copy link
Member

@roji Yes, as we've discussed this should be handled by RelationalTypeMapping.GenerateSqlLiteral (and that in turn could delegate this to a service)

maumar added a commit that referenced this issue Mar 7, 2023
…t - don't wrap the value in json array

Rather than generate a JSON parameter and extract correct value from it, we generate the parameter value directly. Special casing is handled on the provider level by *ModificationCommand and *UpdateSqlGenerator

Fixes #30410
maumar added a commit that referenced this issue Mar 7, 2023
…t - don't wrap the value in json array

Rather than generate a JSON parameter and extract correct value from it, we generate the parameter value directly. Special casing is handled on the provider level by *ModificationCommand and *UpdateSqlGenerator

Fixes #30410
maumar added a commit that referenced this issue Mar 8, 2023
…t - don't wrap the value in json array

Rather than generate a JSON parameter and extract correct value from it, we generate the parameter value directly. Special casing is handled on the provider level by *ModificationCommand and *UpdateSqlGenerator

Fixes #30410
maumar added a commit that referenced this issue Mar 14, 2023
…t - don't wrap the value in json array (#30422)

Rather than generate a JSON parameter and extract correct value from it, we generate the parameter value directly. Special casing is handled on the provider level by *ModificationCommand and *UpdateSqlGenerator

Fixes #30410
@maumar maumar added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Mar 14, 2023
@maumar maumar added this to the 8.0.0 milestone Mar 14, 2023
@ajcvickers ajcvickers modified the milestones: 8.0.0, 8.0.0-preview3 Mar 23, 2023
@ajcvickers ajcvickers modified the milestones: 8.0.0-preview3, 8.0.0 Nov 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
4 participants