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
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<EFCoreVersion>[9.0.0,10.0.0)</EFCoreVersion>
<MicrosoftExtensionsVersion>9.0.0</MicrosoftExtensionsVersion>
<EFCoreVersion>10.0.0-alpha.1.24610.3</EFCoreVersion>
<MicrosoftExtensionsVersion>10.0.0-alpha.1.24609.1</MicrosoftExtensionsVersion>
<NpgsqlVersion>9.0.2</NpgsqlVersion>
</PropertyGroup>

Expand All @@ -23,9 +23,9 @@

<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="xunit" Version="2.9.0" />
<PackageVersion Include="xunit.assert" Version="2.9.0" />
<PackageVersion Include="xunit.core" Version="2.9.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.assert" Version="2.9.2" />
<PackageVersion Include="xunit.core" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="GitHubActionsTestLogger" Version="2.3.3" />
</ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ or PostgresErrorCodes.DuplicateTable
private IReadOnlyList<MigrationCommand> GetCreateIfNotExistsCommands()
=> Dependencies.MigrationsSqlGenerator.Generate([new SqlOperation
{
Sql = GetCreateIfNotExistsScript(),
SuppressTransaction = true
Sql = GetCreateIfNotExistsScript()
}]);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal;

/// <summary>
/// Converts the relational <see cref="NonQueryExpression" /> into a PG-specific <see cref="PgDeleteExpression" />, which
/// Converts the relational <see cref="DeleteExpression" /> into a PG-specific <see cref="PgDeleteExpression" />, which
/// precisely models a DELETE statement in PostgreSQL. This is done to handle the PG-specific USING syntax for table joining.
/// </summary>
public class NpgsqlDeleteConvertingExpressionVisitor : ExpressionVisitor
Expand Down
9 changes: 3 additions & 6 deletions src/EFCore.PG/Query/Internal/NpgsqlQueryCompilationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public NpgsqlQueryCompilationContext(
QueryCompilationContextDependencies dependencies,
RelationalQueryCompilationContextDependencies relationalDependencies,
bool async)
: this(
dependencies, relationalDependencies, async, precompiling: false,
nonNullableReferenceTypeParameters: null)
: this(dependencies, relationalDependencies, async, precompiling: false)
{
}

Expand All @@ -34,9 +32,8 @@ public NpgsqlQueryCompilationContext(
QueryCompilationContextDependencies dependencies,
RelationalQueryCompilationContextDependencies relationalDependencies,
bool async,
bool precompiling,
IReadOnlySet<string>? nonNullableReferenceTypeParameters)
: base(dependencies, relationalDependencies, async, precompiling, nonNullableReferenceTypeParameters)
bool precompiling)
: base(dependencies, relationalDependencies, async, precompiling)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ public virtual QueryCompilationContext Create(bool async)
/// 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 virtual QueryCompilationContext CreatePrecompiled(bool async, IReadOnlySet<string> nonNullableReferenceTypeParameters)
=> new NpgsqlQueryCompilationContext(
_dependencies, _relationalDependencies, async, precompiling: true,
nonNullableReferenceTypeParameters);
public virtual QueryCompilationContext CreatePrecompiled(bool async)
=> new NpgsqlQueryCompilationContext(_dependencies, _relationalDependencies, async, precompiling: true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1096,46 +1096,18 @@ protected override bool IsValidSelectExpressionForExecuteUpdate(
/// 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>
protected override bool IsValidSelectExpressionForExecuteDelete(
SelectExpression selectExpression,
StructuralTypeShaperExpression shaper,
[NotNullWhen(true)] out TableExpression? tableExpression)
{
protected override bool IsValidSelectExpressionForExecuteDelete(SelectExpression selectExpression)
// The default relational behavior is to allow only single-table expressions, and the only permitted feature is a predicate.
// Here we extend this to also inner joins to tables, which we generate via the PostgreSQL-specific USING construct.
if (selectExpression is
{
Orderings: [],
Offset: null,
Limit: null,
GroupBy: [],
Having: null
})
=> selectExpression is
{
TableExpressionBase? table = null;
if (selectExpression.Tables.Count == 1)
{
table = selectExpression.Tables[0];
}
else if (selectExpression.Tables.All(t => t is TableExpression or InnerJoinExpression))
{
var projectionBindingExpression = (ProjectionBindingExpression)shaper.ValueBufferExpression;
var entityProjectionExpression =
(StructuralTypeProjectionExpression)selectExpression.GetProjection(projectionBindingExpression);
var column = entityProjectionExpression.BindProperty(shaper.StructuralType.GetProperties().First());
table = selectExpression.Tables.Select(t => t.UnwrapJoin()).Single(t => t.Alias == column.TableAlias);
}

if (table is TableExpression te)
{
tableExpression = te;
return true;
}
Orderings: [],
Offset: null,
Limit: null,
GroupBy: [],
Having: null
}

tableExpression = null;
return false;
}
&& selectExpression.Tables[0] is TableExpression && selectExpression.Tables.Skip(1).All(t => t is InnerJoinExpression);

// PostgreSQL unnest is guaranteed to return output rows in the same order as its input array,
// https://www.postgresql.org/docs/current/functions-array.html.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,7 @@ private bool TryTranslateStartsEndsWithContains(
return true;
}

case SqlParameterExpression patternParameter
when patternParameter.Name.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal):
case SqlParameterExpression patternParameter:
{
// The pattern is a parameter, register a runtime parameter that will contain the rewritten LIKE pattern, where
// all special characters have been escaped.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private static RelationalTypeMappingParameters CreateParameters(string storeType
var comparer = typeof(TCollection).IsArray && typeof(TCollection).GetArrayRank() > 1
? null // TODO: Value comparer for multidimensional arrays
: (ValueComparer?)Activator.CreateInstance(
elementType.IsNullableValueType()
elementType.IsNullableValueType() || elementMapping.Comparer.Type.IsNullableValueType()
? typeof(ListOfNullableValueTypesComparer<,>)
.MakeGenericType(typeof(TConcreteCollection), elementType.UnwrapNullableType())
: elementType.IsValueType
Expand Down
4 changes: 2 additions & 2 deletions test/EFCore.PG.FunctionalTests/BuiltInDataTypesNpgsqlTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public void Sql_translation_uses_type_mapper_when_parameter()

AssertSql(
"""
@__timeSpan_0='02:01:00' (Nullable = true)
@timeSpan='02:01:00' (Nullable = true)

SELECT m."Int"
FROM "MappedNullableDataTypes" AS m
WHERE m."TimeSpanAsTime" = @__timeSpan_0
WHERE m."TimeSpanAsTime" = @timeSpan
""");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,20 @@ public override async Task Update_complex_type_to_parameter(bool async)

AssertExecuteUpdateSql(
"""
@__complex_type_newAddress_0_AddressLine1='New AddressLine1'
@__complex_type_newAddress_0_AddressLine2='New AddressLine2'
@__complex_type_newAddress_0_Tags={ 'new_tag1', 'new_tag2' } (DbType = Object)
@__complex_type_newAddress_0_ZipCode='99999' (Nullable = true)
@__complex_type_newAddress_0_Code='FR'
@__complex_type_newAddress_0_FullName='France'
@complex_type_newAddress_AddressLine1='New AddressLine1'
@complex_type_newAddress_AddressLine2='New AddressLine2'
@complex_type_newAddress_Tags={ 'new_tag1', 'new_tag2' } (DbType = Object)
@complex_type_newAddress_ZipCode='99999' (Nullable = true)
@complex_type_newAddress_Code='FR'
@complex_type_newAddress_FullName='France'

UPDATE "Customer" AS c
SET "ShippingAddress_AddressLine1" = @__complex_type_newAddress_0_AddressLine1,
"ShippingAddress_AddressLine2" = @__complex_type_newAddress_0_AddressLine2,
"ShippingAddress_Tags" = @__complex_type_newAddress_0_Tags,
"ShippingAddress_ZipCode" = @__complex_type_newAddress_0_ZipCode,
"ShippingAddress_Country_Code" = @__complex_type_newAddress_0_Code,
"ShippingAddress_Country_FullName" = @__complex_type_newAddress_0_FullName
SET "ShippingAddress_AddressLine1" = @complex_type_newAddress_AddressLine1,
"ShippingAddress_AddressLine2" = @complex_type_newAddress_AddressLine2,
"ShippingAddress_Tags" = @complex_type_newAddress_Tags,
"ShippingAddress_ZipCode" = @complex_type_newAddress_ZipCode,
"ShippingAddress_Country_Code" = @complex_type_newAddress_Code,
"ShippingAddress_Country_FullName" = @complex_type_newAddress_FullName
""");
}

Expand All @@ -123,12 +123,12 @@ public override async Task Update_nested_complex_type_to_parameter(bool async)

AssertExecuteUpdateSql(
"""
@__complex_type_newCountry_0_Code='FR'
@__complex_type_newCountry_0_FullName='France'
@complex_type_newCountry_Code='FR'
@complex_type_newCountry_FullName='France'

UPDATE "Customer" AS c
SET "ShippingAddress_Country_Code" = @__complex_type_newCountry_0_Code,
"ShippingAddress_Country_FullName" = @__complex_type_newCountry_0_FullName
SET "ShippingAddress_Country_Code" = @complex_type_newCountry_Code,
"ShippingAddress_Country_FullName" = @complex_type_newCountry_FullName
""");
}

Expand Down Expand Up @@ -186,7 +186,7 @@ public override async Task Update_complex_type_to_another_database_complex_type_

AssertExecuteUpdateSql(
"""
@__p_0='1'
@p='1'

UPDATE "Customer" AS c0
SET "ShippingAddress_AddressLine1" = c1."BillingAddress_AddressLine1",
Expand All @@ -199,7 +199,7 @@ public override async Task Update_complex_type_to_another_database_complex_type_
SELECT c."Id", c."BillingAddress_AddressLine1", c."BillingAddress_AddressLine2", c."BillingAddress_Tags", c."BillingAddress_ZipCode", c."ShippingAddress_Country_Code", c."ShippingAddress_Country_FullName"
FROM "Customer" AS c
ORDER BY c."Id" NULLS FIRST
OFFSET @__p_0
OFFSET @p
) AS c1
WHERE c0."Id" = c1."Id"
""");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public override async Task Delete_with_owned_collection_and_non_natively_transla

AssertSql(
"""
@__p_0='1'
@p='1'

DELETE FROM "Owner" AS o
WHERE o."Id" IN (
SELECT o0."Id"
FROM "Owner" AS o0
ORDER BY o0."Title" NULLS FIRST
OFFSET @__p_0
OFFSET @p
)
""");
}
Expand Down Expand Up @@ -239,6 +239,35 @@ protected class EntityWithPrimitiveCollection
public List<string> Tags { get; set; }
}

public override async Task Delete_with_view_mapping(bool async)
{
await base.Delete_with_view_mapping(async);

AssertSql(
"""
DELETE FROM "Blogs" AS b
""");
}

public override async Task Update_with_view_mapping(bool async)
{
await base.Update_with_view_mapping(async);

AssertSql(
"""
UPDATE "Blogs" AS b
SET "Data" = 'Updated'
""");
}

public override async Task Update_complex_type_with_view_mapping(bool async)
{
await base.Update_complex_type_with_view_mapping(async);

// #34706
AssertSql();
}

private void AssertSql(params string[] expected)
=> TestSqlLoggerFactory.AssertBaseline(expected);

Expand Down
Loading
Loading