Skip to content

Commit aedc60a

Browse files
committed
Sync to EF 10.0.0-rc.1.25416.111
1 parent 0533e60 commit aedc60a

74 files changed

Lines changed: 6154 additions & 3574 deletions

File tree

Some content is hidden

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

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.DS_Store
1+
0.DS_Store
22
*.resources
33
*.suo
44
*.user
@@ -16,3 +16,4 @@ artifacts/
1616
*.ide/
1717
TestResult.xml
1818
.dotnet
19+
.vscode/

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
3-
<EFCoreVersion>10.0.0-preview.7.25380.108</EFCoreVersion>
4-
<MicrosoftExtensionsVersion>10.0.0-preview.7.25380.108</MicrosoftExtensionsVersion>
3+
<EFCoreVersion>10.0.0-rc.1.25416.111</EFCoreVersion>
4+
<MicrosoftExtensionsVersion>10.0.0-rc.1.25416.111</MicrosoftExtensionsVersion>
55
<NpgsqlVersion>9.0.3</NpgsqlVersion>
66
</PropertyGroup>
77

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": "10.0.100-preview.5.25277.114",
3+
"version": "10.0.100-preview.7.25380.108",
44
"rollForward": "latestMajor",
55
"allowPrerelease": true
66
}

src/EFCore.PG/Query/Internal/NpgsqlParameterBasedSqlProcessor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ public NpgsqlParameterBasedSqlProcessor(
2727
/// any release. You should only use it directly in your code with extreme caution and knowing that
2828
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2929
/// </summary>
30-
public override Expression Process(Expression queryExpression, CacheSafeParameterFacade parametersFacade)
30+
public override Expression Process(Expression queryExpression, ParametersCacheDecorator parametersDecorator)
3131
{
32-
queryExpression = base.Process(queryExpression, parametersFacade);
32+
queryExpression = base.Process(queryExpression, parametersDecorator);
3333

3434
queryExpression = new NpgsqlDeleteConvertingExpressionVisitor().Process(queryExpression);
3535

3636
return queryExpression;
3737
}
3838

3939
/// <inheritdoc />
40-
protected override Expression ProcessSqlNullability(Expression selectExpression, CacheSafeParameterFacade parametersFacade)
41-
=> new NpgsqlSqlNullabilityProcessor(Dependencies, Parameters).Process(selectExpression, parametersFacade);
40+
protected override Expression ProcessSqlNullability(Expression selectExpression, ParametersCacheDecorator parametersDecorator)
41+
=> new NpgsqlSqlNullabilityProcessor(Dependencies, Parameters).Process(selectExpression, parametersDecorator);
4242
}

src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp
10691069
{
10701070
// This case is for when a nested JSON entity is being accessed. We want the json/jsonb fragment in this case (not text),
10711071
// so we can perform further JSON operations on it.
1072-
case NpgsqlOwnedJsonTypeMapping:
1072+
case NpgsqlStructuralJsonTypeMapping:
10731073
GenerateJsonPath(returnsText: false);
10741074
break;
10751075

src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,14 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr
199199
};
200200

201201
var jsonTypeMapping = jsonQueryExpression.JsonColumn.TypeMapping!;
202-
Check.DebugAssert(jsonTypeMapping is NpgsqlOwnedJsonTypeMapping, "JSON column has a non-JSON mapping");
202+
Check.DebugAssert(jsonTypeMapping is NpgsqlStructuralJsonTypeMapping, "JSON column has a non-JSON mapping");
203203

204204
// We now add all of projected entity's the properties and navigations into the jsonb_to_recordset's AS clause, which defines the
205205
// names and types of columns to come out of the JSON fragments.
206206
var columnInfos = new List<PgTableValuedFunctionExpression.ColumnInfo>();
207207

208208
// We're only interested in properties which actually exist in the JSON, filter out uninteresting shadow keys
209-
foreach (var property in GetAllPropertiesInHierarchy(jsonQueryExpression.EntityType))
209+
foreach (var property in jsonQueryExpression.StructuralType.GetPropertiesInHierarchy())
210210
{
211211
if (property.GetJsonPropertyName() is string jsonPropertyName)
212212
{
@@ -218,18 +218,37 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr
218218
}
219219
}
220220

221-
// Navigations represent nested JSON owned entities, which we also add to the AS clause, but with the JSON type.
222-
foreach (var navigation in GetAllNavigationsInHierarchy(jsonQueryExpression.EntityType)
223-
.Where(
224-
n => n.ForeignKey.IsOwnership
225-
&& n.TargetEntityType.IsMappedToJson()
226-
&& n.ForeignKey.PrincipalToDependent == n))
221+
switch (jsonQueryExpression.StructuralType)
227222
{
228-
var jsonNavigationName = navigation.TargetEntityType.GetJsonPropertyName();
229-
Check.DebugAssert(jsonNavigationName is not null, $"No JSON property name for navigation {navigation.Name}");
223+
case IEntityType entityType:
224+
foreach (var navigation in entityType.GetNavigationsInHierarchy()
225+
.Where(n => n.ForeignKey.IsOwnership
226+
&& n.TargetEntityType.IsMappedToJson()
227+
&& n.ForeignKey.PrincipalToDependent == n))
228+
{
229+
var jsonNavigationName = navigation.TargetEntityType.GetJsonPropertyName();
230+
Check.DebugAssert(jsonNavigationName is not null, $"No JSON property name for navigation {navigation.Name}");
231+
232+
columnInfos.Add(
233+
new PgTableValuedFunctionExpression.ColumnInfo { Name = jsonNavigationName, TypeMapping = jsonTypeMapping });
234+
}
235+
236+
break;
237+
238+
case IComplexType complexType:
239+
foreach (var complexProperty in complexType.GetComplexProperties())
240+
{
241+
var jsonPropertyName = complexProperty.ComplexType.GetJsonPropertyName();
242+
Check.DebugAssert(jsonPropertyName is not null, $"No JSON property name for complex property {complexProperty.Name}");
230243

231-
columnInfos.Add(
232-
new PgTableValuedFunctionExpression.ColumnInfo { Name = jsonNavigationName, TypeMapping = jsonTypeMapping });
244+
columnInfos.Add(
245+
new PgTableValuedFunctionExpression.ColumnInfo { Name = jsonPropertyName, TypeMapping = jsonTypeMapping });
246+
}
247+
248+
break;
249+
250+
default:
251+
throw new UnreachableException();
233252
}
234253

235254
// json_to_recordset requires the nested JSON document - it does not accept a path within a containing JSON document (like SQL
@@ -254,21 +273,12 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr
254273
return new ShapedQueryExpression(
255274
selectExpression,
256275
new RelationalStructuralTypeShaperExpression(
257-
jsonQueryExpression.EntityType,
276+
jsonQueryExpression.StructuralType,
258277
new ProjectionBindingExpression(
259278
selectExpression,
260279
new ProjectionMember(),
261280
typeof(ValueBuffer)),
262281
false));
263-
264-
// TODO: Move these to IEntityType?
265-
static IEnumerable<IProperty> GetAllPropertiesInHierarchy(IEntityType entityType)
266-
=> entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive())
267-
.SelectMany(t => t.GetDeclaredProperties());
268-
269-
static IEnumerable<INavigation> GetAllNavigationsInHierarchy(IEntityType entityType)
270-
=> entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive())
271-
.SelectMany(t => t.GetDeclaredNavigations());
272282
}
273283

274284
/// <summary>

src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,5 +737,5 @@ private static bool MayContainNulls(SqlExpression arrayExpression)
737737
// Note that we can check parameter values for null since we cache by the parameter nullability; but we cannot do the same for bool.
738738
private bool IsNull(SqlExpression? expression)
739739
=> expression is SqlConstantExpression { Value: null }
740-
|| expression is SqlParameterExpression { Name: string parameterName } && ParametersFacade.IsParameterNull(parameterName);
740+
|| expression is SqlParameterExpression { Name: string parameterName } && ParametersDecorator.IsNull(parameterName);
741741
}

src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,40 @@ when binaryExpression.Left.Type.UnwrapNullableType().FullName == "NodaTime.Local
300300
// further JSON operations may need to be composed. However, when the value extracted is a JSON null, a non-NULL jsonb value is
301301
// returned, and comparing that to relational NULL returns false.
302302
// Pattern-match this and force the use of ->> by changing the mapping to be a scalar rather than an entity type.
303-
case SqlUnaryExpression
303+
case SqlBinaryExpression
304304
{
305305
OperatorType: ExpressionType.Equal or ExpressionType.NotEqual,
306-
Operand: JsonScalarExpression { TypeMapping: NpgsqlOwnedJsonTypeMapping } operand
307-
} unary:
306+
Left: JsonScalarExpression { TypeMapping: NpgsqlStructuralJsonTypeMapping } operand,
307+
Right: SqlConstantExpression { Value: null }
308+
} binary:
308309
{
309-
return unary.Update(
310+
return binary.Update(
311+
new JsonScalarExpression(
312+
operand.Json, operand.Path, operand.Type, _typeMappingSource.FindMapping("text"), operand.IsNullable),
313+
binary.Right);
314+
}
315+
case SqlBinaryExpression
316+
{
317+
OperatorType: ExpressionType.Equal or ExpressionType.NotEqual,
318+
Left: SqlConstantExpression { Value: null },
319+
Right: JsonScalarExpression { TypeMapping: NpgsqlStructuralJsonTypeMapping } operand
320+
} binary:
321+
{
322+
return binary.Update(
323+
binary.Left,
310324
new JsonScalarExpression(
311325
operand.Json, operand.Path, operand.Type, _typeMappingSource.FindMapping("text"), operand.IsNullable));
312326
}
327+
// Unfortunately EF isn't consistent in its representation of X IS NULL in the SQL tree - sometimes it's a SqlUnaryExpression with Equals,
328+
// sometimes it's an X = NULL SqlBinaryExpression that later gets transformed to SqlUnaryExpression, in SqlNullabilityProcessor. We recognize
329+
// both of these here.
330+
case SqlUnaryExpression
331+
{
332+
Operand: JsonScalarExpression { TypeMapping: NpgsqlStructuralJsonTypeMapping } operand
333+
} unary:
334+
return unary.Update(
335+
new JsonScalarExpression(
336+
operand.Json, operand.Path, operand.Type, _typeMappingSource.FindMapping("text"), operand.IsNullable));
313337
}
314338

315339
return translation;

src/EFCore.PG/Storage/Internal/Mapping/NpgsqlJsonTypeMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
66
/// <summary>
77
/// Supports the older Npgsql-specific JSON mapping, allowing mapping json/jsonb to text, to e.g.
88
/// <see cref="JsonElement" /> (weakly-typed mapping) or to arbitrary POCOs (but without them being modeled).
9-
/// For the standard EF JSON support, which relies on owned entity modeling, see <see cref="NpgsqlOwnedJsonTypeMapping" />.
9+
/// For the standard EF JSON support, which relies on owned entity modeling, see <see cref="NpgsqlStructuralJsonTypeMapping" />.
1010
/// </summary>
1111
public class NpgsqlJsonTypeMapping : NpgsqlTypeMapping
1212
{

src/EFCore.PG/Storage/Internal/Mapping/NpgsqlOwnedJsonTypeMapping.cs renamed to src/EFCore.PG/Storage/Internal/Mapping/NpgsqlStructuralJsonTypeMapping.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
66

77
/// <summary>
8-
/// Supports the standard EF JSON support, which relies on owned entity modeling.
8+
/// Supports the standard EF JSON support, which relies on owned entity or complex type modeling.
99
/// See <see cref="NpgsqlJsonTypeMapping" /> for the older Npgsql-specific support, which allows mapping json/jsonb to text, to e.g.
1010
/// <see cref="JsonElement" /> (weakly-typed mapping) or to arbitrary POCOs (but without them being modeled).
1111
/// </summary>
12-
public class NpgsqlOwnedJsonTypeMapping : JsonTypeMapping
12+
public class NpgsqlStructuralJsonTypeMapping : JsonTypeMapping
1313
{
1414
/// <summary>
1515
/// The database type used by Npgsql (<see cref="NpgsqlDbType.Json" /> or <see cref="NpgsqlDbType.Jsonb" />.
@@ -34,7 +34,7 @@ private static readonly ConstructorInfo MemoryStreamConstructor
3434
/// any release. You should only use it directly in your code with extreme caution and knowing that
3535
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3636
/// </summary>
37-
public NpgsqlOwnedJsonTypeMapping(string storeType)
37+
public NpgsqlStructuralJsonTypeMapping(string storeType)
3838
: base(storeType, typeof(JsonElement), dbType: null)
3939
{
4040
NpgsqlDbType = storeType switch
@@ -74,7 +74,7 @@ public override Expression CustomizeDataReaderExpression(Expression expression)
7474
/// any release. You should only use it directly in your code with extreme caution and knowing that
7575
/// doing so can result in application failures when updating to a new Entity Framework Core release.
7676
/// </summary>
77-
protected NpgsqlOwnedJsonTypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType)
77+
protected NpgsqlStructuralJsonTypeMapping(RelationalTypeMappingParameters parameters, NpgsqlDbType npgsqlDbType)
7878
: base(parameters)
7979
{
8080
NpgsqlDbType = npgsqlDbType;
@@ -91,7 +91,7 @@ protected override void ConfigureParameter(DbParameter parameter)
9191
if (parameter is not NpgsqlParameter npgsqlParameter)
9292
{
9393
throw new InvalidOperationException(
94-
$"Npgsql-specific type mapping {nameof(NpgsqlOwnedJsonTypeMapping)} being used with non-Npgsql parameter type {parameter.GetType().Name}");
94+
$"Npgsql-specific type mapping {nameof(NpgsqlStructuralJsonTypeMapping)} being used with non-Npgsql parameter type {parameter.GetType().Name}");
9595
}
9696

9797
base.ConfigureParameter(parameter);
@@ -114,7 +114,7 @@ protected virtual string EscapeSqlLiteral(string literal)
114114
/// doing so can result in application failures when updating to a new Entity Framework Core release.
115115
/// </summary>
116116
protected override string GenerateNonNullSqlLiteral(object value)
117-
=> $"'{EscapeSqlLiteral(JsonSerializer.Serialize(value))}'";
117+
=> $"'{EscapeSqlLiteral((string)value)}'";
118118

119119
/// <summary>
120120
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -123,5 +123,5 @@ protected override string GenerateNonNullSqlLiteral(object value)
123123
/// doing so can result in application failures when updating to a new Entity Framework Core release.
124124
/// </summary>
125125
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
126-
=> new NpgsqlOwnedJsonTypeMapping(parameters, NpgsqlDbType);
126+
=> new NpgsqlStructuralJsonTypeMapping(parameters, NpgsqlDbType);
127127
}

0 commit comments

Comments
 (0)