Skip to content

Commit

Permalink
Fix parameter names for nested types in complex type equality (#33527)
Browse files Browse the repository at this point in the history
Fixes #33449
  • Loading branch information
roji authored Apr 16, 2024
1 parent 1267c39 commit 89e9446
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;

Expand Down Expand Up @@ -2068,11 +2069,18 @@ when sqlParameterExpression.Name.StartsWith(QueryCompilationContext.QueryParamet
Expression.Constant(property, typeof(IProperty))),
QueryCompilationContext.QueryContextParameter);

var newParameterName =
$"{RuntimeParameterPrefix}"
+ $"{chainExpression.ParameterExpression.Name[QueryCompilationContext.QueryParameterPrefix.Length..]}_{property.Name}";
var parameterNameBuilder = new StringBuilder(RuntimeParameterPrefix)
.Append(chainExpression.ParameterExpression.Name[QueryCompilationContext.QueryParameterPrefix.Length..])
.Append('_');

return _queryCompilationContext.RegisterRuntimeParameter(newParameterName, lambda);
foreach (var complexProperty in chainExpression.ComplexPropertyChain)
{
parameterNameBuilder.Append(complexProperty.Name).Append('_');
}

parameterNameBuilder.Append(property.Name);

return _queryCompilationContext.RegisterRuntimeParameter(parameterNameBuilder.ToString(), lambda);
}

case MemberInitExpression memberInitExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class InMemoryComplianceTest : ComplianceTestBase
{
// No in-memory tests
typeof(ComplexTypeQueryTestBase<>),
typeof(AdHocComplexTypeQueryTestBase),
typeof(PrimitiveCollectionsQueryTestBase<>),
typeof(NonSharedPrimitiveCollectionsQueryTestBase),
typeof(FunkyDataQueryTestBase<>),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Query;

// ReSharper disable ClassNeverInstantiated.Local

public abstract class AdHocComplexTypeQueryTestBase : NonSharedModelTestBase
{
#region 33449

[ConditionalFact]
public virtual async Task Complex_type_equals_parameter_with_nested_types_with_property_of_same_name()
{
var contextFactory = await InitializeAsync<Context33449>(
seed: context =>
{
context.AddRange(
new Context33449.EntityType
{
ComplexContainer = new()
{
Id = 1,
Containee1 = new() { Id = 2 },
Containee2 = new() { Id = 3 }
}
});
return context.SaveChangesAsync();
});

await using var context = contextFactory.CreateContext();

var container = new Context33449.ComplexContainer
{
Id = 1,
Containee1 = new() { Id = 2 },
Containee2 = new() { Id = 3 }
};

_ = await context.Set<Context33449.EntityType>().Where(b => b.ComplexContainer == container).SingleAsync();
}

private class Context33449(DbContextOptions options) : DbContext(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<EntityType>().ComplexProperty(b => b.ComplexContainer, x =>
{
x.ComplexProperty(c => c.Containee1);
x.ComplexProperty(c => c.Containee2);
});

public class EntityType
{
public int Id { get; set; }
public ComplexContainer ComplexContainer { get; set; } = null!;
}

public class ComplexContainer
{
public int Id { get; set; }

public ComplexContainee1 Containee1 { get; set; } = null!;
public ComplexContainee2 Containee2 { get; set; } = null!;
}

public class ComplexContainee1
{
public int Id { get; set; }
}

public class ComplexContainee2
{
public int Id { get; set; }
}
}

#endregion 33449

protected override string StoreName
=> "AdHocComplexTypeQueryTest";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Query;

public class AdHocComplexTypeQuerySqlServerTest : AdHocComplexTypeQueryTestBase
{
public override async Task Complex_type_equals_parameter_with_nested_types_with_property_of_same_name()
{
await base.Complex_type_equals_parameter_with_nested_types_with_property_of_same_name();

AssertSql(
"""
@__entity_equality_container_0_Id='1' (Nullable = true)
@__entity_equality_container_0_Containee1_Id='2' (Nullable = true)
@__entity_equality_container_0_Containee2_Id='3' (Nullable = true)

SELECT TOP(2) [e].[Id], [e].[ComplexContainer_Id], [e].[ComplexContainer_Containee1_Id], [e].[ComplexContainer_Containee2_Id]
FROM [EntityType] AS [e]
WHERE [e].[ComplexContainer_Id] = @__entity_equality_container_0_Id AND [e].[ComplexContainer_Containee1_Id] = @__entity_equality_container_0_Containee1_Id AND [e].[ComplexContainer_Containee2_Id] = @__entity_equality_container_0_Containee2_Id
""");
}

protected TestSqlLoggerFactory TestSqlLoggerFactory
=> (TestSqlLoggerFactory)ListLoggerFactory;

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

protected override ITestStoreFactory TestStoreFactory
=> SqlServerTestStoreFactory.Instance;
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,12 @@ public override async Task Complex_type_equals_parameter(bool async)
@__entity_equality_address_0_AddressLine1='804 S. Lakeshore Road' (Size = 4000)
@__entity_equality_address_0_Tags='["foo","bar"]' (Size = 4000)
@__entity_equality_address_0_ZipCode='38654' (Nullable = true)
@__entity_equality_address_0_Code='US' (Size = 4000)
@__entity_equality_address_0_FullName='United States' (Size = 4000)
@__entity_equality_address_0_Country_Code='US' (Size = 4000)
@__entity_equality_address_0_Country_FullName='United States' (Size = 4000)

SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_Tags], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName]
FROM [Customer] AS [c]
WHERE [c].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [c].[ShippingAddress_AddressLine2] IS NULL AND [c].[ShippingAddress_Tags] = @__entity_equality_address_0_Tags AND [c].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [c].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Code AND [c].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_FullName
WHERE [c].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [c].[ShippingAddress_AddressLine2] IS NULL AND [c].[ShippingAddress_Tags] = @__entity_equality_address_0_Tags AND [c].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [c].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Country_Code AND [c].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_Country_FullName
""");
}

Expand All @@ -268,15 +268,15 @@ public override async Task Contains_over_complex_type(bool async)
@__entity_equality_address_0_AddressLine1='804 S. Lakeshore Road' (Size = 4000)
@__entity_equality_address_0_Tags='["foo","bar"]' (Size = 4000)
@__entity_equality_address_0_ZipCode='38654' (Nullable = true)
@__entity_equality_address_0_Code='US' (Size = 4000)
@__entity_equality_address_0_FullName='United States' (Size = 4000)
@__entity_equality_address_0_Country_Code='US' (Size = 4000)
@__entity_equality_address_0_Country_FullName='United States' (Size = 4000)

SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_Tags], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName]
FROM [Customer] AS [c]
WHERE EXISTS (
SELECT 1
FROM [Customer] AS [c0]
WHERE [c0].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [c0].[ShippingAddress_AddressLine2] IS NULL AND [c0].[ShippingAddress_Tags] = @__entity_equality_address_0_Tags AND [c0].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [c0].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Code AND [c0].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_FullName)
WHERE [c0].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [c0].[ShippingAddress_AddressLine2] IS NULL AND [c0].[ShippingAddress_Tags] = @__entity_equality_address_0_Tags AND [c0].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [c0].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Country_Code AND [c0].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_Country_FullName)
""");
}

Expand Down Expand Up @@ -604,12 +604,12 @@ public override async Task Struct_complex_type_equals_parameter(bool async)
"""
@__entity_equality_address_0_AddressLine1='804 S. Lakeshore Road' (Size = 4000)
@__entity_equality_address_0_ZipCode='38654' (Nullable = true)
@__entity_equality_address_0_Code='US' (Size = 4000)
@__entity_equality_address_0_FullName='United States' (Size = 4000)
@__entity_equality_address_0_Country_Code='US' (Size = 4000)
@__entity_equality_address_0_Country_FullName='United States' (Size = 4000)

SELECT [v].[Id], [v].[Name], [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v].[ShippingAddress_AddressLine1], [v].[ShippingAddress_AddressLine2], [v].[ShippingAddress_ZipCode], [v].[ShippingAddress_Country_Code], [v].[ShippingAddress_Country_FullName]
FROM [ValuedCustomer] AS [v]
WHERE [v].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [v].[ShippingAddress_AddressLine2] IS NULL AND [v].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [v].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Code AND [v].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_FullName
WHERE [v].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [v].[ShippingAddress_AddressLine2] IS NULL AND [v].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [v].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Country_Code AND [v].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_Country_FullName
""");
}

Expand All @@ -628,15 +628,15 @@ public override async Task Contains_over_struct_complex_type(bool async)
"""
@__entity_equality_address_0_AddressLine1='804 S. Lakeshore Road' (Size = 4000)
@__entity_equality_address_0_ZipCode='38654' (Nullable = true)
@__entity_equality_address_0_Code='US' (Size = 4000)
@__entity_equality_address_0_FullName='United States' (Size = 4000)
@__entity_equality_address_0_Country_Code='US' (Size = 4000)
@__entity_equality_address_0_Country_FullName='United States' (Size = 4000)

SELECT [v].[Id], [v].[Name], [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v].[ShippingAddress_AddressLine1], [v].[ShippingAddress_AddressLine2], [v].[ShippingAddress_ZipCode], [v].[ShippingAddress_Country_Code], [v].[ShippingAddress_Country_FullName]
FROM [ValuedCustomer] AS [v]
WHERE EXISTS (
SELECT 1
FROM [ValuedCustomer] AS [v0]
WHERE [v0].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [v0].[ShippingAddress_AddressLine2] IS NULL AND [v0].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [v0].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Code AND [v0].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_FullName)
WHERE [v0].[ShippingAddress_AddressLine1] = @__entity_equality_address_0_AddressLine1 AND [v0].[ShippingAddress_AddressLine2] IS NULL AND [v0].[ShippingAddress_ZipCode] = @__entity_equality_address_0_ZipCode AND [v0].[ShippingAddress_Country_Code] = @__entity_equality_address_0_Country_Code AND [v0].[ShippingAddress_Country_FullName] = @__entity_equality_address_0_Country_FullName)
""");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Query;

public class AdHocComplexTypeQuerySqliteTest : AdHocComplexTypeQueryTestBase
{
protected override ITestStoreFactory TestStoreFactory
=> SqliteTestStoreFactory.Instance;
}
Loading

0 comments on commit 89e9446

Please sign in to comment.