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
Original file line number Diff line number Diff line change
Expand Up @@ -80,68 +80,73 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp

var innerExpression = root.UnwrapTypeConversion(out var convertedType);
var structuralTypeReference = UnwrapStructuralTypeReference(innerExpression);
var entityReference = structuralTypeReference as EntityReference;
if (entityReference is not null)

ITypeBase structuralType;

switch (structuralTypeReference)
{
var entityType = entityReference.EntityType;
if (convertedType != null)
{
entityType = entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive())
.FirstOrDefault(et => et.ClrType == convertedType);
if (entityType == null)
case EntityReference { EntityType: var entityType } entityReference:
if (convertedType != null)
{
return null;
entityType = entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive())
.FirstOrDefault(et => et.ClrType == convertedType);
if (entityType == null)
{
return null;
}
}
}

var navigation = memberIdentity.MemberInfo is not null
? entityType.FindNavigation(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? entityType.FindNavigation(memberIdentity.Name)
: null;
if (navigation is not null)
{
return ExpandNavigation(root, entityReference, navigation, convertedType is not null);
}
// Attempt to bind navigations; these are only relevant to entity types
var navigation = memberIdentity.MemberInfo is not null
? entityType.FindNavigation(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? entityType.FindNavigation(memberIdentity.Name)
: null;
if (navigation is not null)
{
return ExpandNavigation(root, entityReference, navigation, convertedType is not null);
}

var skipNavigation = memberIdentity.MemberInfo is not null
? entityType.FindSkipNavigation(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? entityType.FindSkipNavigation(memberIdentity.Name)
: null;
if (skipNavigation is not null)
{
return ExpandSkipNavigation(root, entityReference, skipNavigation, convertedType is not null);
}
var skipNavigation = memberIdentity.MemberInfo is not null
? entityType.FindSkipNavigation(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? entityType.FindSkipNavigation(memberIdentity.Name)
: null;
if (skipNavigation is not null)
{
return ExpandSkipNavigation(root, entityReference, skipNavigation, convertedType is not null);
}

structuralType = entityType;
break;

case ComplexTypeReference { ComplexType: var complexType }:
structuralType = complexType;
break;

default:
return null;
}

var structuralType = entityReference is not null
? (ITypeBase)entityReference.EntityType
: structuralTypeReference is ComplexTypeReference complexTypeReference
? complexTypeReference.ComplexType
// Attempt to bind complex and primitive collection properties; these are common to both entity and complex types
var complexProperty = memberIdentity.MemberInfo != null
? structuralType.FindComplexProperty(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? structuralType.FindComplexProperty(memberIdentity.Name)
: null;

if (structuralType is not null)
if (complexProperty is not null)
{
var complexProperty = memberIdentity.MemberInfo != null
? structuralType.FindComplexProperty(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? structuralType.FindComplexProperty(memberIdentity.Name)
: null;
if (complexProperty is not null)
{
return new ComplexPropertyReference(root, complexProperty, originalExpression);
}
return new ComplexPropertyReference(root, complexProperty, originalExpression);
}

var property = memberIdentity.MemberInfo != null
? structuralType.FindProperty(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? structuralType.FindProperty(memberIdentity.Name)
: null;
if (property?.IsPrimitiveCollection == true)
{
return new PrimitiveCollectionReference(root, property);
}
var property = memberIdentity.MemberInfo != null
? structuralType.FindProperty(memberIdentity.MemberInfo)
: memberIdentity.Name is not null
? structuralType.FindProperty(memberIdentity.Name)
: null;
if (property?.IsPrimitiveCollection == true)
{
return new PrimitiveCollectionReference(root, property);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,20 @@ public override Task Using_is_operator_with_of_type_on_multiple_type_with_no_res
SELECT VALUE c
FROM root c
WHERE ((c["Discriminator"] IN ("Eagle", "Kiwi") AND (c["Discriminator"] = "Kiwi")) AND (c["Discriminator"] = "Eagle"))
""");
});

public override Task Primitive_collection_on_subtype(bool async)
=> Fixture.NoSyncTest(
async, async a =>
{
await base.Primitive_collection_on_subtype(a);

AssertSql(
"""
SELECT VALUE c
FROM root c
WHERE (c["Discriminator"] IN (0, 1, 2, 3) AND (ARRAY_LENGTH(c["Ints"]) > 0))
""");
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ public InheritanceQueryFixtureBase()
Assert.Equal(ee.SugarGrams, aa.SugarGrams);
Assert.Equal(ee.CaffeineGrams, aa.CaffeineGrams);
Assert.Equal(ee.Carbonation, aa.Carbonation);
Assert.Equal(ee.Ints, aa.Ints);

AssertComplexType(ee.ParentComplexType, aa.ParentComplexType);
AssertComplexType(ee.ChildComplexType, aa.ChildComplexType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,13 @@ public virtual Task GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(bo
async,
ss => ss.Set<Animal>().Where(e => typeof(Kiwi) != e.GetType()));

[ConditionalTheory, MemberData(nameof(IsAsyncData))]
public virtual Task Primitive_collection_on_subtype(bool async)
=> AssertQuery(
async,
ss => ss.Set<Drink>().Where(d => ((Coke)d).Ints.Any()),
ss => ss.Set<Drink>().Where(d => d is Coke && ((Coke)d).Ints.Any()));

protected InheritanceContext CreateContext()
=> Fixture.CreateContext();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class Coke : Drink, ISugary
public int CaffeineGrams { get; set; }
public int Carbonation { get; set; }

// Samep roperty name as on Tea, to test uniquification
public required int[] Ints { get; set; }

// Same property name as on Tea, to test uniquification
public ComplexType? ChildComplexType { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public static IReadOnlyList<Drink> CreateDrinks(bool useGeneratedKeys)
SugarGrams = 6,
CaffeineGrams = 4,
Carbonation = 5,
Ints = [8, 9],
ChildComplexType = new ComplexType
{
UniqueInt = 100,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public override async Task Can_query_when_shared_column(bool async)

AssertSql(
"""
SELECT TOP(2) [d].[Id], [d].[Discriminator], [d].[SortIndex], [d].[CaffeineGrams], [d].[CokeCO2], [d].[SugarGrams], [d].[ComplexTypeCollection], [d].[ParentComplexType_Int], [d].[ParentComplexType_UniqueInt], [d].[ParentComplexType_Nested_NestedInt], [d].[ParentComplexType_Nested_UniqueInt], [d].[ChildComplexType_Int], [d].[ChildComplexType_UniqueInt], [d].[ChildComplexType_Nested_NestedInt], [d].[ChildComplexType_Nested_UniqueInt]
SELECT TOP(2) [d].[Id], [d].[Discriminator], [d].[SortIndex], [d].[CaffeineGrams], [d].[CokeCO2], [d].[Ints], [d].[SugarGrams], [d].[ComplexTypeCollection], [d].[ParentComplexType_Int], [d].[ParentComplexType_UniqueInt], [d].[ParentComplexType_Nested_NestedInt], [d].[ParentComplexType_Nested_UniqueInt], [d].[ChildComplexType_Int], [d].[ChildComplexType_UniqueInt], [d].[ChildComplexType_Nested_NestedInt], [d].[ChildComplexType_Nested_UniqueInt]
FROM [Drinks] AS [d]
WHERE [d].[Discriminator] = 1
""",
Expand Down Expand Up @@ -94,7 +94,7 @@ public override async Task Can_query_all_types_when_shared_column(bool async)

AssertSql(
"""
SELECT [d].[Id], [d].[Discriminator], [d].[SortIndex], [d].[CaffeineGrams], [d].[CokeCO2], [d].[SugarGrams], [d].[LiltCO2], [d].[HasMilk], [d].[ComplexTypeCollection], [d].[ParentComplexType_Int], [d].[ParentComplexType_UniqueInt], [d].[ParentComplexType_Nested_NestedInt], [d].[ParentComplexType_Nested_UniqueInt], [d].[ChildComplexType_Int], [d].[ChildComplexType_UniqueInt], [d].[ChildComplexType_Nested_NestedInt], [d].[ChildComplexType_Nested_UniqueInt], [d].[Tea_ChildComplexType_Int], [d].[Tea_ChildComplexType_UniqueInt], [d].[Tea_ChildComplexType_Nested_NestedInt], [d].[Tea_ChildComplexType_Nested_UniqueInt]
SELECT [d].[Id], [d].[Discriminator], [d].[SortIndex], [d].[CaffeineGrams], [d].[CokeCO2], [d].[Ints], [d].[SugarGrams], [d].[LiltCO2], [d].[HasMilk], [d].[ComplexTypeCollection], [d].[ParentComplexType_Int], [d].[ParentComplexType_UniqueInt], [d].[ParentComplexType_Nested_NestedInt], [d].[ParentComplexType_Nested_UniqueInt], [d].[ChildComplexType_Int], [d].[ChildComplexType_UniqueInt], [d].[ChildComplexType_Nested_NestedInt], [d].[ChildComplexType_Nested_UniqueInt], [d].[Tea_ChildComplexType_Int], [d].[Tea_ChildComplexType_UniqueInt], [d].[Tea_ChildComplexType_Nested_NestedInt], [d].[Tea_ChildComplexType_Nested_UniqueInt]
FROM [Drinks] AS [d]
WHERE [d].[Discriminator] IN (0, 1, 2, 3)
""");
Expand Down Expand Up @@ -769,6 +769,20 @@ WHERE [a].[Discriminator] IN (N'Eagle', N'Kiwi') AND [a].[Discriminator] <> N'Ki
""");
}

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

AssertSql(
"""
SELECT [d].[Id], [d].[Discriminator], [d].[SortIndex], [d].[CaffeineGrams], [d].[CokeCO2], [d].[Ints], [d].[SugarGrams], [d].[LiltCO2], [d].[HasMilk], [d].[ComplexTypeCollection], [d].[ParentComplexType_Int], [d].[ParentComplexType_UniqueInt], [d].[ParentComplexType_Nested_NestedInt], [d].[ParentComplexType_Nested_UniqueInt], [d].[ChildComplexType_Int], [d].[ChildComplexType_UniqueInt], [d].[ChildComplexType_Nested_NestedInt], [d].[ChildComplexType_Nested_UniqueInt], [d].[Tea_ChildComplexType_Int], [d].[Tea_ChildComplexType_UniqueInt], [d].[Tea_ChildComplexType_Nested_NestedInt], [d].[Tea_ChildComplexType_Nested_UniqueInt]
FROM [Drinks] AS [d]
WHERE [d].[Discriminator] IN (0, 1, 2, 3) AND EXISTS (
SELECT 1
FROM OPENJSON([d].[Ints]) AS [i])
""");
}

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