Skip to content

Commit 5d93d51

Browse files
committed
Structural equality support for complex JSON
Part of #36296
1 parent d2b21a0 commit 5d93d51

File tree

68 files changed

+3513
-526
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3513
-526
lines changed

src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs

Lines changed: 255 additions & 50 deletions
Large diffs are not rendered by default.

src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ when _columnsToRewrite.TryGetValue((columnExpression.TableAlias, columnExpressio
261261
// with OPENJSON.
262262
return openJsonExpression.JsonExpression.TypeMapping
263263
is SqlServerStringTypeMapping { StoreType: "json" }
264-
or SqlServerOwnedJsonTypeMapping { StoreType: "json" }
264+
or SqlServerStructuralJsonTypeMapping { StoreType: "json" }
265265
? openJsonExpression.Update(
266266
new SqlUnaryExpression(
267267
ExpressionType.Convert,

src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp
522522
return jsonScalarExpression;
523523
}
524524

525-
if (jsonScalarExpression.TypeMapping is SqlServerOwnedJsonTypeMapping
525+
if (jsonScalarExpression.TypeMapping is SqlServerStructuralJsonTypeMapping
526526
|| jsonScalarExpression.TypeMapping?.ElementTypeMapping is not null)
527527
{
528528
Sql.Append("JSON_QUERY(");
@@ -541,7 +541,7 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp
541541
GenerateJsonPath(jsonScalarExpression.Path);
542542
Sql.Append(")");
543543

544-
if (jsonScalarExpression.TypeMapping is not SqlServerOwnedJsonTypeMapping and not StringTypeMapping)
544+
if (jsonScalarExpression.TypeMapping is not SqlServerStructuralJsonTypeMapping and not StringTypeMapping)
545545
{
546546
Sql.Append(" AS ");
547547
Sql.Append(jsonScalarExpression.TypeMapping!.StoreType);

src/EFCore.SqlServer/Storage/Internal/SqlServerOwnedJsonTypeMapping.cs renamed to src/EFCore.SqlServer/Storage/Internal/SqlServerStructuralJsonTypeMapping.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
1414
/// any release. You should only use it directly in your code with extreme caution and knowing that
1515
/// doing so can result in application failures when updating to a new Entity Framework Core release.
1616
/// </summary>
17-
public class SqlServerOwnedJsonTypeMapping : JsonTypeMapping
17+
public class SqlServerStructuralJsonTypeMapping : JsonTypeMapping
1818
{
1919
private static readonly MethodInfo CreateUtf8StreamMethod
20-
= typeof(SqlServerOwnedJsonTypeMapping).GetMethod(nameof(CreateUtf8Stream), [typeof(string)])!;
20+
= typeof(SqlServerStructuralJsonTypeMapping).GetMethod(nameof(CreateUtf8Stream), [typeof(string)])!;
2121

2222
private static readonly MethodInfo GetStringMethod
2323
= typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetString), [typeof(int)])!;
@@ -28,23 +28,23 @@ private static readonly MethodInfo GetStringMethod
2828
/// any release. You should only use it directly in your code with extreme caution and knowing that
2929
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3030
/// </summary>
31-
public static SqlServerOwnedJsonTypeMapping Default { get; } = new("nvarchar(max)");
31+
public static SqlServerStructuralJsonTypeMapping Default { get; } = new("nvarchar(max)");
3232

3333
/// <summary>
3434
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
3535
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
3636
/// any release. You should only use it directly in your code with extreme caution and knowing that
3737
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3838
/// </summary>
39-
public static SqlServerOwnedJsonTypeMapping OwnedJsonTypeDefault { get; } = new("json");
39+
public static SqlServerStructuralJsonTypeMapping JsonTypeDefault { get; } = new("json");
4040

4141
/// <summary>
4242
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
4343
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
4444
/// any release. You should only use it directly in your code with extreme caution and knowing that
4545
/// doing so can result in application failures when updating to a new Entity Framework Core release.
4646
/// </summary>
47-
public SqlServerOwnedJsonTypeMapping(string storeType)
47+
public SqlServerStructuralJsonTypeMapping(string storeType)
4848
: base(storeType, typeof(JsonTypePlaceholder), System.Data.DbType.String)
4949
{
5050
}
@@ -84,7 +84,7 @@ public override Expression CustomizeDataReaderExpression(Expression expression)
8484
/// any release. You should only use it directly in your code with extreme caution and knowing that
8585
/// doing so can result in application failures when updating to a new Entity Framework Core release.
8686
/// </summary>
87-
protected SqlServerOwnedJsonTypeMapping(RelationalTypeMappingParameters parameters)
87+
protected SqlServerStructuralJsonTypeMapping(RelationalTypeMappingParameters parameters)
8888
: base(parameters)
8989
{
9090
}
@@ -105,7 +105,7 @@ 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+
=> $"'{EscapeSqlLiteral((string)value)}'";
109109

110110
/// <summary>
111111
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -114,7 +114,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
114114
/// doing so can result in application failures when updating to a new Entity Framework Core release.
115115
/// </summary>
116116
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
117-
=> new SqlServerOwnedJsonTypeMapping(parameters);
117+
=> new SqlServerStructuralJsonTypeMapping(parameters);
118118

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

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,8 @@ public SqlServerTypeMappingSource(
244244
if (clrType == typeof(JsonTypePlaceholder))
245245
{
246246
return storeTypeName == "json"
247-
? SqlServerOwnedJsonTypeMapping.OwnedJsonTypeDefault
248-
: SqlServerOwnedJsonTypeMapping.Default;
247+
? SqlServerStructuralJsonTypeMapping.JsonTypeDefault
248+
: SqlServerStructuralJsonTypeMapping.Default;
249249
}
250250

251251
if (storeTypeName != null)

src/EFCore.SqlServer/Update/Internal/SqlServerModificationCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ protected override void ProcessSinglePropertyJsonUpdate(ref ColumnModificationPa
8484
parameters = parameters with
8585
{
8686
Value = value,
87-
TypeMapping = parameters.TypeMapping is SqlServerOwnedJsonTypeMapping
87+
TypeMapping = parameters.TypeMapping is SqlServerStructuralJsonTypeMapping
8888
? SqlServerStringTypeMapping.UnicodeDefault
8989
: parameters.TypeMapping
9090
};

src/EFCore.Sqlite.Core/Storage/Internal/SqliteJsonTypeMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public override Expression CustomizeDataReaderExpression(Expression expression)
8484
/// doing so can result in application failures when updating to a new Entity Framework Core release.
8585
/// </summary>
8686
protected override string GenerateNonNullSqlLiteral(object value)
87-
=> $"'{EscapeSqlLiteral(JsonSerializer.Serialize(value))}'";
87+
=> $"'{EscapeSqlLiteral((string)value)}'";
8888

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

src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ private void ReorderOriginalComplexCollectionEntries(IComplexProperty complexPro
10131013

10141014
var originalEntries = GetComplexCollectionOriginalEntries(complexProperty);
10151015
var elementToOriginalEntry = new Dictionary<object, InternalComplexEntry>(ReferenceEqualityComparer.Instance);
1016-
1016+
10171017
// Build mapping of existing non-null elements to their entries
10181018
for (var i = 0; i < originalEntries.Count && i < oldOriginalCollection.Count; i++)
10191019
{

test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsCollectionCosmosTest.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ FROM root c
4141
WHERE ((
4242
SELECT VALUE COUNT(1)
4343
FROM r IN c["RelatedCollection"]
44-
WHERE (r["Int"] != 50)) = 2)
44+
WHERE (r["Int"] != 8)) = 2)
4545
""");
4646
});
4747

@@ -59,7 +59,7 @@ FROM root c
5959
WHERE (ARRAY(
6060
SELECT VALUE r["Int"]
6161
FROM r IN c["RelatedCollection"]
62-
ORDER BY r["Id"])[0] = 21)
62+
ORDER BY r["Id"])[0] = 8)
6363
""");
6464
}
6565
}
@@ -74,7 +74,7 @@ public override Task Index_constant(bool async)
7474
"""
7575
SELECT VALUE c
7676
FROM root c
77-
WHERE (c["RelatedCollection"][0]["Int"] = 21)
77+
WHERE (c["RelatedCollection"][0]["Int"] = 8)
7878
""");
7979
});
8080

@@ -90,7 +90,7 @@ public override Task Index_parameter(bool async)
9090
9191
SELECT VALUE c
9292
FROM root c
93-
WHERE (c["RelatedCollection"][@i]["Int"] = 21)
93+
WHERE (c["RelatedCollection"][@i]["Int"] = 8)
9494
""");
9595
});
9696

@@ -105,7 +105,7 @@ public override async Task Index_column(bool async)
105105
"""
106106
SELECT VALUE c
107107
FROM root c
108-
WHERE (c["RelatedCollection"][(c["Id"] - 1)]["Int"] = 21)
108+
WHERE (c["RelatedCollection"][(c["Id"] - 1)]["Int"] = 8)
109109
""");
110110
}
111111
}
@@ -120,7 +120,7 @@ public override async Task Index_out_of_bounds(bool async)
120120
"""
121121
SELECT VALUE c
122122
FROM root c
123-
WHERE (c["RelatedCollection"][9999]["Int"] = 50)
123+
WHERE (c["RelatedCollection"][9999]["Int"] = 8)
124124
""");
125125
}
126126
}

test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsMiscellaneousCosmosTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public override Task Where_optional_related_property(bool async)
3636
"""
3737
SELECT VALUE c
3838
FROM root c
39-
WHERE (c["OptionalRelated"]["Int"] = 9)
39+
WHERE (c["OptionalRelated"]["Int"] = 8)
4040
""");
4141
});
4242

@@ -50,7 +50,7 @@ public override Task Where_nested_related_property(bool async)
5050
"""
5151
SELECT VALUE c
5252
FROM root c
53-
WHERE (c["RequiredRelated"]["RequiredNested"]["Int"] = 50)
53+
WHERE (c["RequiredRelated"]["RequiredNested"]["Int"] = 8)
5454
""");
5555
});
5656

0 commit comments

Comments
 (0)