Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project>
<PropertyGroup>
<EFCoreVersion>11.0.0-preview.1.26104.118</EFCoreVersion>
<MicrosoftExtensionsVersion>11.0.0-preview.1.26104.118</MicrosoftExtensionsVersion>
<EFCoreVersion>11.0.0-preview.2.26116.101</EFCoreVersion>
<MicrosoftExtensionsVersion>11.0.0-preview.2.26116.101</MicrosoftExtensionsVersion>
<MicrosoftExtensionsConfigurationVersion>11.0.0-preview.2.26078.113</MicrosoftExtensionsConfigurationVersion>
<NpgsqlVersion>10.0.0</NpgsqlVersion>
</PropertyGroup>

Expand All @@ -16,8 +17,8 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational.Specification.Tests" Version="[$(EFCoreVersion)]" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="[$(EFCoreVersion)]" />

<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsConfigurationVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsVersion)" />

<PackageVersion Include="Npgsql" Version="$(NpgsqlVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static bool TryExtractJsonArray(
TableValuedFunctionExpression
{
Name: "jsonb_array_elements_text" or "json_array_elements_text",
Arguments: [var json]
Arguments: [SqlExpression json]
} tvf
],
GroupBy: [],
Expand Down
285 changes: 121 additions & 164 deletions src/EFCore.PG/Infrastructure/Internal/NpgsqlModelValidator.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal;
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </para>
/// </remarks>
public class PgTableValuedFunctionExpression : TableValuedFunctionExpression, IEquatable<PgTableValuedFunctionExpression>
public class PgTableValuedFunctionExpression(
string alias,
string name,
IReadOnlyList<Expression> arguments,
IReadOnlyList<PgTableValuedFunctionExpression.ColumnInfo>? columnInfos = null,
bool withOrdinality = true) : TableValuedFunctionExpression(alias, name, schema: null, builtIn: true, arguments), IEquatable<PgTableValuedFunctionExpression>
{
/// <summary>
/// The name of the column to be projected out from the <c>unnest</c> call.
Expand All @@ -32,7 +37,7 @@ public class PgTableValuedFunctionExpression : TableValuedFunctionExpression, IE
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </remarks>
public virtual IReadOnlyList<ColumnInfo>? ColumnInfos { get; }
public virtual IReadOnlyList<ColumnInfo>? ColumnInfos { get; } = columnInfos;

/// <summary>
/// Whether to project an additional ordinality column containing the index of each element in the array.
Expand All @@ -43,25 +48,7 @@ public class PgTableValuedFunctionExpression : TableValuedFunctionExpression, IE
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </remarks>
public virtual bool WithOrdinality { get; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public PgTableValuedFunctionExpression(
string alias,
string name,
IReadOnlyList<SqlExpression> arguments,
IReadOnlyList<ColumnInfo>? columnInfos = null,
bool withOrdinality = true)
: base(alias, name, schema: null, builtIn: true, arguments)
{
ColumnInfos = columnInfos;
WithOrdinality = withOrdinality;
}
public virtual bool WithOrdinality { get; } = withOrdinality;

/// <inheritdoc />
protected override Expression VisitChildren(ExpressionVisitor visitor)
Expand All @@ -75,18 +62,18 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override PgTableValuedFunctionExpression Update(IReadOnlyList<SqlExpression> arguments)
public override PgTableValuedFunctionExpression Update(IReadOnlyList<Expression> arguments)
=> arguments.SequenceEqual(Arguments, ReferenceEqualityComparer.Instance)
? this
: new PgTableValuedFunctionExpression(Alias, Name, arguments, ColumnInfos, WithOrdinality);

/// <inheritdoc />
public override TableExpressionBase Clone(string? alias, ExpressionVisitor cloningExpressionVisitor)
{
var arguments = new SqlExpression[Arguments.Count];
var arguments = new Expression[Arguments.Count];
for (var i = 0; i < arguments.Length; i++)
{
arguments[i] = (SqlExpression)cloningExpressionVisitor.Visit(Arguments[i]);
arguments[i] = cloningExpressionVisitor.Visit(Arguments[i]);
}

return new PgTableValuedFunctionExpression(Alias, Name, arguments, ColumnInfos, WithOrdinality);
Expand Down
10 changes: 4 additions & 6 deletions src/EFCore.PG/Query/Expressions/Internal/PgUnnestExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public class PgUnnestExpression : PgTableValuedFunctionExpression
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </remarks>
public virtual SqlExpression Array
=> Arguments[0];
public virtual SqlExpression Array { get; }

/// <summary>
/// The name of the column to be projected out from the <c>unnest</c> call.
Expand All @@ -60,8 +59,7 @@ public PgUnnestExpression(string alias, SqlExpression array, string columnName,

private PgUnnestExpression(string alias, SqlExpression array, ColumnInfo? columnInfo, bool withOrdinality = true)
: base(alias, "unnest", [array], columnInfo is null ? null : [columnInfo.Value], withOrdinality)
{
}
=> Array = array;

/// <inheritdoc />
protected override Expression VisitChildren(ExpressionVisitor visitor)
Expand All @@ -75,8 +73,8 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override PgUnnestExpression Update(IReadOnlyList<SqlExpression> arguments)
=> arguments is [var singleArgument]
public override PgUnnestExpression Update(IReadOnlyList<Expression> arguments)
=> arguments is [SqlExpression singleArgument]
? Update(singleArgument)
: throw new ArgumentException();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
/// See <see cref="NpgsqlJsonTypeMapping" /> for the older Npgsql-specific support, which allows mapping json/jsonb to text, to e.g.
/// <see cref="JsonElement" /> (weakly-typed mapping) or to arbitrary POCOs (but without them being modeled).
/// </summary>
public class NpgsqlStructuralJsonTypeMapping : JsonTypeMapping
public class NpgsqlStructuralJsonTypeMapping : StructuralJsonTypeMapping
{
/// <summary>
/// The database type used by Npgsql (<see cref="NpgsqlDbType.Json" /> or <see cref="NpgsqlDbType.Jsonb" />.
Expand Down
3 changes: 2 additions & 1 deletion test/EFCore.PG.FunctionalTests/NpgsqlComplianceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ public class NpgsqlComplianceTest : RelationalComplianceTestBase
protected override ICollection<Type> IgnoredTestBases { get; } = new HashSet<Type>
{
// Not implemented
typeof(CompiledModelTestBase), typeof(CompiledModelRelationalTestBase), // #3087
typeof(CompiledModelTestBase),
typeof(CompiledModelRelationalTestBase), // #3087
typeof(FromSqlSprocQueryTestBase<>),
typeof(UdfDbFunctionTestBase<>),
typeof(UpdateSqlGeneratorTestBase),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public override async Task Select_unmapped_associate_scalar_property(QueryTracki

AssertSql(
"""
SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate"
SELECT r."RequiredAssociate"
FROM "RootEntity" AS r
""");
}
Expand Down Expand Up @@ -279,6 +279,20 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra
""");
}

public override async Task Select_associate_and_target_to_index_based_binding_via_closure(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_associate_and_target_to_index_based_binding_via_closure(queryTrackingBehavior);

if (queryTrackingBehavior is not QueryTrackingBehavior.TrackAll)
{
AssertSql(
"""
SELECT r."Id", r."RequiredAssociate"
FROM "RootEntity" AS r
""");
}
}

#endregion Multiple

#region Subquery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public override async Task Select_unmapped_associate_scalar_property(QueryTracki

AssertSql(
"""
SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
SELECT r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
FROM "RootEntity" AS r
""");
}
Expand Down Expand Up @@ -191,7 +191,7 @@ public override async Task Select_nested_collection_on_required_associate(QueryT

AssertSql(
"""
SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
SELECT r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
FROM "RootEntity" AS r
ORDER BY r."Id" NULLS FIRST
""");
Expand All @@ -203,7 +203,7 @@ public override async Task Select_nested_collection_on_optional_associate(QueryT

AssertSql(
"""
SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
SELECT r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String"
FROM "RootEntity" AS r
ORDER BY r."Id" NULLS FIRST
""");
Expand Down Expand Up @@ -248,6 +248,17 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra
""");
}

public override async Task Select_associate_and_target_to_index_based_binding_via_closure(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_associate_and_target_to_index_based_binding_via_closure(queryTrackingBehavior);

AssertSql(
"""
SELECT r."Id", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String"
FROM "RootEntity" AS r
""");
}

#endregion Multiple

#region Subquery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,22 @@ LEFT JOIN (
""");
}

public override async Task Select_associate_and_target_to_index_based_binding_via_closure(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_associate_and_target_to_index_based_binding_via_closure(queryTrackingBehavior);

AssertSql(
"""
SELECT r."Id", a."Id", a."CollectionRootId", a."Int", a."Ints", a."Name", a."OptionalNestedAssociateId", a."RequiredNestedAssociateId", a."String", n."Id", n0."Id", n1."Id", n1."CollectionAssociateId", n1."Int", n1."Ints", n1."Name", n1."String", n."CollectionAssociateId", n."Int", n."Ints", n."Name", n."String", n0."CollectionAssociateId", n0."Int", n0."Ints", n0."Name", n0."String"
FROM "RootEntity" AS r
INNER JOIN "AssociateType" AS a ON r."RequiredAssociateId" = a."Id"
LEFT JOIN "NestedAssociateType" AS n ON a."OptionalNestedAssociateId" = n."Id"
INNER JOIN "NestedAssociateType" AS n0 ON a."RequiredNestedAssociateId" = n0."Id"
LEFT JOIN "NestedAssociateType" AS n1 ON a."Id" = n1."CollectionAssociateId"
ORDER BY r."Id" NULLS FIRST, a."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST
""");
}

#endregion Multiple

#region Subquery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,20 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra
""");
}

public override async Task Select_associate_and_target_to_index_based_binding_via_closure(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_associate_and_target_to_index_based_binding_via_closure(queryTrackingBehavior);

if (queryTrackingBehavior is not QueryTrackingBehavior.TrackAll)
{
AssertSql(
"""
SELECT r."Id", r."RequiredAssociate"
FROM "RootEntity" AS r
""");
}
}

#endregion Multiple

#region Subquery
Expand Down
Loading
Loading