Skip to content

Commit cb71c34

Browse files
CopilotAndriySvyryd
andcommitted
Fix double escaping of Chinese characters in JSON columns during updates
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
1 parent dc87c70 commit cb71c34

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

src/EFCore.SqlServer/Storage/Internal/SqlServerOwnedJsonTypeMapping.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ protected virtual string EscapeSqlLiteral(string literal)
105105
/// doing so can result in application failures when updating to a new Entity Framework Core release.
106106
/// </summary>
107107
protected override string GenerateNonNullSqlLiteral(object value)
108-
=> $"'{EscapeSqlLiteral(JsonSerializer.Serialize(value))}'";
108+
{
109+
var jsonString = value is string str ? str : JsonSerializer.Serialize(value);
110+
return $"'{EscapeSqlLiteral(jsonString)}'";
111+
}
109112

110113
/// <summary>
111114
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3633,6 +3633,40 @@ public virtual Task Add_and_update_nested_optional_primitive_collection(bool? va
36333633
}
36343634
});
36353635

3636+
[ConditionalFact]
3637+
public virtual Task Edit_single_property_with_chinese_characters()
3638+
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
3639+
CreateContext,
3640+
UseTransaction,
3641+
async context =>
3642+
{
3643+
var query = await context.JsonEntitiesBasic.ToListAsync();
3644+
var entity = query.Single(x => x.Id == 1);
3645+
entity.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething = "测试1";
3646+
3647+
ClearLog();
3648+
await context.SaveChangesAsync();
3649+
},
3650+
async context =>
3651+
{
3652+
var result = await context.Set<JsonEntityBasic>().SingleAsync(x => x.Id == 1);
3653+
Assert.Equal("测试1", result.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething);
3654+
},
3655+
async context =>
3656+
{
3657+
var query = await context.JsonEntitiesBasic.ToListAsync();
3658+
var entity = query.Single(x => x.Id == 1);
3659+
entity.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething = "测试2";
3660+
3661+
ClearLog();
3662+
await context.SaveChangesAsync();
3663+
},
3664+
async context =>
3665+
{
3666+
var result = await context.Set<JsonEntityBasic>().SingleAsync(x => x.Id == 1);
3667+
Assert.Equal("测试2", result.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething);
3668+
});
3669+
36363670
public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
36373671
=> facade.UseTransaction(transaction.GetDbTransaction());
36383672

test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateSqlServerTest.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,46 @@ public override Task Edit_single_property_collection_of_collection_of_nullable_i
25352535
public override Task Edit_single_property_collection_of_collection_of_single()
25362536
=> Assert.ThrowsAsync<ArgumentOutOfRangeException>(base.Edit_single_property_collection_of_collection_of_single);
25372537

2538+
public override async Task Edit_single_property_with_chinese_characters()
2539+
{
2540+
await base.Edit_single_property_with_chinese_characters();
2541+
2542+
AssertSql(
2543+
"""
2544+
@p0='{"Name":"Root","Number":7,"OwnedCollectionBranch":[],"OwnedReferenceBranch":{"Date":"2101-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":10.1,"Id":10,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"测试1"}}}' (Nullable = false) (Size = 386)
2545+
@p1='1'
2546+
2547+
SET IMPLICIT_TRANSACTIONS OFF;
2548+
SET NOCOUNT ON;
2549+
UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = @p0
2550+
OUTPUT 1
2551+
WHERE [Id] = @p1;
2552+
""",
2553+
//
2554+
"""
2555+
SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot]
2556+
FROM [JsonEntitiesBasic] AS [j]
2557+
WHERE [j].[Id] = 1
2558+
""",
2559+
//
2560+
"""
2561+
@p0='{"Name":"Root","Number":7,"OwnedCollectionBranch":[],"OwnedReferenceBranch":{"Date":"2101-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":10.1,"Id":10,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"测试2"}}}' (Nullable = false) (Size = 386)
2562+
@p1='1'
2563+
2564+
SET IMPLICIT_TRANSACTIONS OFF;
2565+
SET NOCOUNT ON;
2566+
UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = @p0
2567+
OUTPUT 1
2568+
WHERE [Id] = @p1;
2569+
""",
2570+
//
2571+
"""
2572+
SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot]
2573+
FROM [JsonEntitiesBasic] AS [j]
2574+
WHERE [j].[Id] = 1
2575+
""");
2576+
}
2577+
25382578
protected override void ClearLog()
25392579
=> Fixture.TestSqlLoggerFactory.Clear();
25402580

0 commit comments

Comments
 (0)