Skip to content

Commit f76ddae

Browse files
rojiCopilot
andcommitted
Sync to EF 11.0.0-preview.4.26210.110
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent db8279c commit f76ddae

6 files changed

Lines changed: 181 additions & 103 deletions

File tree

Directory.Packages.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
3-
<EFCoreVersion>11.0.0-preview.4.26203.108</EFCoreVersion>
4-
<MicrosoftExtensionsVersion>11.0.0-preview.4.26203.108</MicrosoftExtensionsVersion>
5-
<MicrosoftExtensionsConfigurationVersion>11.0.0-preview.4.26203.108</MicrosoftExtensionsConfigurationVersion>
3+
<EFCoreVersion>11.0.0-preview.4.26210.110</EFCoreVersion>
4+
<MicrosoftExtensionsVersion>11.0.0-preview.4.26210.110</MicrosoftExtensionsVersion>
5+
<MicrosoftExtensionsConfigurationVersion>11.0.0-preview.4.26210.110</MicrosoftExtensionsConfigurationVersion>
66
<NpgsqlVersion>10.0.0</NpgsqlVersion>
77
</PropertyGroup>
88

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "11.0.100-preview.2.26159.112",
3+
"version": "11.0.100-preview.4.26210.111",
44
"rollForward": "latestMinor",
55
"allowPrerelease": true
66
}

src/EFCore.PG/Update/Internal/NpgsqlUpdateSqlGenerator.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,12 @@ protected override void AppendUpdateColumnValue(
127127
string name,
128128
string? schema)
129129
{
130-
if (columnModification.JsonPath is not (null or "$"))
130+
if (columnModification.JsonPath is null or { IsRoot: true })
131+
{
132+
base.AppendUpdateColumnValue(updateSqlGeneratorHelper, columnModification, stringBuilder, name, schema);
133+
return;
134+
}
135+
131136
{
132137
Check.DebugAssert(
133138
columnModification.TypeMapping is NpgsqlStructuralJsonTypeMapping,
@@ -141,45 +146,33 @@ protected override void AppendUpdateColumnValue(
141146

142147
Check.DebugAssert(columnModification.TypeMapping.StoreType is "jsonb", "Non-jsonb type mapping in JSON partial update");
143148

149+
var jsonPath = columnModification.JsonPath;
150+
144151
// TODO: Lax or not?
145152
stringBuilder
146153
.Append("jsonb_set(")
147154
.Append(updateSqlGeneratorHelper.DelimitIdentifier(columnModification.ColumnName))
148155
.Append(", '{");
149156

150-
// TODO: Unfortunately JsonPath is provided as a JSONPATH string, but PG's jsonb_set requires the path as an array.
151-
// Parse the components back out (https://github.com/dotnet/efcore/issues/32185)
152-
var components = columnModification.JsonPath.Split(".");
157+
// PG's jsonb_set requires the path as an array, so we iterate over the structured JsonPath segments.
158+
var ordinalIndex = 0;
153159
var needsComma = false;
154-
for (var i = 0; i < components.Length; i++)
160+
foreach (var segment in jsonPath.Segments)
155161
{
156162
if (needsComma)
157163
{
158164
stringBuilder.Append(',');
159165
}
160166

161-
var component = components[i];
162-
var bracketOpen = component.IndexOf('[');
163-
if (bracketOpen == -1)
167+
if (segment.IsArray)
164168
{
165-
if (i > 0) // The first component is $, representing the root
166-
{
167-
stringBuilder.Append(component);
168-
needsComma = true;
169-
}
170-
171-
continue;
169+
stringBuilder.Append(jsonPath.Ordinals[ordinalIndex++]);
172170
}
173-
174-
var propertyName = component[..bracketOpen];
175-
if (i > 0) // The first component is $, representing the root
171+
else
176172
{
177-
stringBuilder
178-
.Append(propertyName)
179-
.Append(',');
173+
stringBuilder.Append(segment.PropertyName);
180174
}
181175

182-
stringBuilder.Append(component[(bracketOpen + 1)..^1]);
183176
needsComma = true;
184177
}
185178

@@ -197,10 +190,6 @@ protected override void AppendUpdateColumnValue(
197190

198191
stringBuilder.Append(")");
199192
}
200-
else
201-
{
202-
base.AppendUpdateColumnValue(updateSqlGeneratorHelper, columnModification, stringBuilder, name, schema);
203-
}
204193
}
205194

206195
private FieldInfo? _columnModificationValueField;
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Xunit.Sdk;
5+
6+
namespace Microsoft.EntityFrameworkCore.Query.Associations.Navigations;
7+
8+
public class NavigationsBulkUpdateNpgsqlTest(NavigationsNpgsqlFixture fixture, ITestOutputHelper testOutputHelper)
9+
: NavigationsBulkUpdateRelationalTestBase<NavigationsNpgsqlFixture>(fixture, testOutputHelper)
10+
{
11+
[ConditionalFact]
12+
public virtual void Check_all_tests_overridden()
13+
=> TestHelpers.AssertAllMethodsOverridden(GetType());
14+
15+
// FK constraint failures
16+
public override Task Delete_entity_with_associations()
17+
=> Assert.ThrowsAsync<PostgresException>(base.Delete_entity_with_associations);
18+
19+
public override Task Delete_required_associate()
20+
=> Assert.ThrowsAsync<PostgresException>(base.Delete_required_associate);
21+
22+
public override Task Delete_optional_associate()
23+
=> Assert.ThrowsAsync<PostgresException>(base.Delete_optional_associate);
24+
25+
// PostgreSQL generates valid SQL for these but produces wrong row counts due to self-joins in UPDATE ... FROM
26+
public override Task Update_property_inside_associate()
27+
=> Assert.ThrowsAsync<EqualException>(base.Update_property_inside_associate);
28+
29+
public override Task Update_property_inside_associate_with_special_chars()
30+
=> Assert.ThrowsAsync<EqualException>(base.Update_property_inside_associate_with_special_chars);
31+
32+
public override Task Update_property_on_projected_associate()
33+
=> Assert.ThrowsAsync<EqualException>(base.Update_property_on_projected_associate);
34+
35+
public override Task Update_property_on_projected_associate_with_OrderBy_Skip()
36+
=> Assert.ThrowsAsync<EqualException>(base.Update_property_on_projected_associate_with_OrderBy_Skip);
37+
38+
public override Task Update_multiple_properties_inside_same_associate()
39+
=> Assert.ThrowsAsync<EqualException>(base.Update_multiple_properties_inside_same_associate);
40+
41+
public override Task Update_primitive_collection_to_constant()
42+
=> Assert.ThrowsAsync<EqualException>(base.Update_primitive_collection_to_constant);
43+
44+
public override Task Update_primitive_collection_to_parameter()
45+
=> Assert.ThrowsAsync<EqualException>(base.Update_primitive_collection_to_parameter);
46+
47+
// Translation not yet supported for navigation-mapped associations
48+
public override Task Update_associate_to_parameter()
49+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_parameter);
50+
51+
public override Task Update_associate_to_inline()
52+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_inline);
53+
54+
public override Task Update_associate_to_inline_with_lambda()
55+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_inline_with_lambda);
56+
57+
public override Task Update_associate_to_another_associate()
58+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_another_associate);
59+
60+
public override Task Update_associate_to_null()
61+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_null);
62+
63+
public override Task Update_associate_to_null_with_lambda()
64+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_null_with_lambda);
65+
66+
public override Task Update_associate_to_null_parameter()
67+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_associate_to_null_parameter);
68+
69+
public override Task Update_nested_associate_to_parameter()
70+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_associate_to_parameter);
71+
72+
public override Task Update_nested_associate_to_inline_with_lambda()
73+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_associate_to_inline_with_lambda);
74+
75+
public override Task Update_nested_associate_to_another_nested_associate()
76+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_associate_to_another_nested_associate);
77+
78+
public override Task Update_nested_collection_to_parameter()
79+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_collection_to_parameter);
80+
81+
public override Task Update_nested_collection_to_inline_with_lambda()
82+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_collection_to_inline_with_lambda);
83+
84+
public override Task Update_nested_collection_to_another_nested_collection()
85+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_nested_collection_to_another_nested_collection);
86+
87+
public override Task Update_collection_to_parameter()
88+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_collection_to_parameter);
89+
90+
public override Task Update_collection_referencing_the_original_collection()
91+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_collection_referencing_the_original_collection);
92+
93+
public override Task Update_primitive_collection_to_another_collection()
94+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_primitive_collection_to_another_collection);
95+
96+
public override Task Update_inside_structural_collection()
97+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_inside_structural_collection);
98+
99+
public override Task Update_multiple_properties_inside_associates_and_on_entity_type()
100+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_multiple_properties_inside_associates_and_on_entity_type);
101+
102+
public override Task Update_multiple_projected_associates_via_anonymous_type()
103+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_multiple_projected_associates_via_anonymous_type);
104+
105+
public override async Task Update_property_inside_nested_associate()
106+
{
107+
await base.Update_property_inside_nested_associate();
108+
109+
AssertExecuteUpdateSql(
110+
"""
111+
@p='foo_updated'
112+
113+
UPDATE "NestedAssociateType" AS n
114+
SET "String" = @p
115+
FROM "RootEntity" AS r
116+
INNER JOIN "AssociateType" AS a ON r."RequiredAssociateId" = a."Id"
117+
WHERE a."RequiredNestedAssociateId" = n."Id"
118+
""");
119+
}
120+
121+
public override async Task Update_associate_with_null_required_property()
122+
{
123+
await base.Update_associate_with_null_required_property();
124+
125+
AssertExecuteUpdateSql();
126+
}
127+
128+
public override async Task Update_required_nested_associate_to_null()
129+
{
130+
await base.Update_required_nested_associate_to_null();
131+
132+
AssertExecuteUpdateSql();
133+
}
134+
135+
public override Task Update_inside_primitive_collection()
136+
=> Assert.ThrowsAsync<InvalidOperationException>(base.Update_inside_primitive_collection);
137+
}

test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,7 @@ public override async Task Where()
3939
FROM "RootEntity" AS r
4040
WHERE (
4141
SELECT count(*)::int
42-
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS (
43-
"Id" integer,
44-
"Int" integer,
45-
"Ints" jsonb,
46-
"Name" text,
47-
"String" text
48-
)) WITH ORDINALITY AS a
42+
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS ("Int" integer)) WITH ORDINALITY AS a
4943
WHERE a."Int" <> 8) = 2
5044
""");
5145
}
@@ -62,10 +56,7 @@ public override async Task OrderBy_ElementAt()
6256
SELECT a."Int"
6357
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS (
6458
"Id" integer,
65-
"Int" integer,
66-
"Ints" jsonb,
67-
"Name" text,
68-
"String" text
59+
"Int" integer
6960
)) WITH ORDINALITY AS a
7061
ORDER BY a."Id" NULLS FIRST
7162
LIMIT 1 OFFSET 0) = 8
@@ -210,18 +201,12 @@ public override async Task GroupBy()
210201
SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate"
211202
FROM "RootEntity" AS r
212203
WHERE 16 IN (
213-
SELECT COALESCE(sum(a0."Int"), 0)::int
214-
FROM (
215-
SELECT a."Id" AS "Id0", a."Int", a."Ints", a."Name", a."String", a."String" AS "Key"
216-
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS (
217-
"Id" integer,
218-
"Int" integer,
219-
"Ints" jsonb,
220-
"Name" text,
221-
"String" text
222-
)) WITH ORDINALITY AS a
223-
) AS a0
224-
GROUP BY a0."Key"
204+
SELECT COALESCE(sum(a."Int"), 0)::int
205+
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS (
206+
"Int" integer,
207+
"String" text
208+
)) WITH ORDINALITY AS a
209+
GROUP BY a."String"
225210
)
226211
""");
227212
}
@@ -248,13 +233,7 @@ SELECT r."Name"
248233
FROM "RootEntity" AS r
249234
WHERE EXISTS (
250235
SELECT 1
251-
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS (
252-
"Id" integer,
253-
"Int" integer,
254-
"Ints" jsonb,
255-
"Name" text,
256-
"String" text
257-
)) WITH ORDINALITY AS a
236+
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS ("Int" integer)) WITH ORDINALITY AS a
258237
WHERE a."Int" > 0)
259238
GROUP BY r."Name"
260239
) AS r1
@@ -265,13 +244,7 @@ LEFT JOIN (
265244
FROM "RootEntity" AS r0
266245
WHERE EXISTS (
267246
SELECT 1
268-
FROM ROWS FROM (jsonb_to_recordset(r0."AssociateCollection") AS (
269-
"Id" integer,
270-
"Int" integer,
271-
"Ints" jsonb,
272-
"Name" text,
273-
"String" text
274-
)) WITH ORDINALITY AS a0
247+
FROM ROWS FROM (jsonb_to_recordset(r0."AssociateCollection") AS ("Int" integer)) WITH ORDINALITY AS a0
275248
WHERE a0."Int" > 0)
276249
) AS r2
277250
WHERE r2.row <= 1
@@ -291,13 +264,7 @@ public override async Task Select_within_Select_within_Select_with_aggregates()
291264
SELECT (
292265
SELECT COALESCE(sum((
293266
SELECT max(n."Int")
294-
FROM ROWS FROM (jsonb_to_recordset(a."NestedCollection") AS (
295-
"Id" integer,
296-
"Int" integer,
297-
"Ints" jsonb,
298-
"Name" text,
299-
"String" text
300-
)) WITH ORDINALITY AS n)), 0)::int
267+
FROM ROWS FROM (jsonb_to_recordset(a."NestedCollection") AS ("Int" integer)) WITH ORDINALITY AS n)), 0)::int
301268
FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS ("NestedCollection" jsonb)) WITH ORDINALITY AS a)
302269
FROM "RootEntity" AS r
303270
""");

0 commit comments

Comments
 (0)