Skip to content

Commit

Permalink
Query: Allow property access on derived type by using type casting
Browse files Browse the repository at this point in the history
Resolves #15807
Resolves #15848 (Since client eval for projection is already added)
  • Loading branch information
smitpatel committed Jun 5, 2019
1 parent 7f7130a commit 21865b6
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,54 @@ protected override Expression VisitExtension(Expression node)

protected override Expression VisitMember(MemberExpression memberExpression)
{
var innerExpression = Visit(memberExpression.Expression);
if (innerExpression is EntityShaperExpression entityShaper)
if (memberExpression.Expression is EntityShaperExpression
|| (memberExpression.Expression is UnaryExpression innerUnaryExpression
&& innerUnaryExpression.NodeType == ExpressionType.Convert
&& innerUnaryExpression.Operand is EntityShaperExpression))
{
return BindProperty(entityShaper, entityShaper.EntityType.FindProperty(memberExpression.Member.GetSimpleMemberName()));
return BindProperty(memberExpression.Expression, memberExpression.Member.GetSimpleMemberName());
}

var innerExpression = Visit(memberExpression.Expression);

return TranslationFailed(memberExpression.Expression, innerExpression)
? null
: _memberTranslatorProvider.Translate((SqlExpression)innerExpression, memberExpression.Member, memberExpression.Type);
}

private SqlExpression BindProperty(Expression source, string propertyName)
{
Type convertedType = null;
if (source is UnaryExpression unaryExpression
&& unaryExpression.NodeType == ExpressionType.Convert)
{
source = unaryExpression.Operand;
if (unaryExpression.Type != typeof(object))
{
convertedType = unaryExpression.Type;
}
}

if (source is EntityShaperExpression entityShaper)
{
var entityType = entityShaper.EntityType;
if (convertedType != null)
{
entityType = entityType.RootType().GetDerivedTypesInclusive()
.FirstOrDefault(et => et.ClrType == convertedType);

if (entityType == null)
{
return null;
}
}

return BindProperty(entityShaper, entityType.FindProperty(propertyName));
}

throw new InvalidOperationException();
}

private SqlExpression BindProperty(EntityShaperExpression entityShaper, IProperty property)
{
return ((SelectExpression)entityShaper.ValueBufferExpression.QueryExpression)
Expand Down Expand Up @@ -133,35 +170,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
{
if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName))
{
Type convertedType = null;
if (source is UnaryExpression unaryExpression
&& unaryExpression.NodeType == ExpressionType.Convert)
{
source = unaryExpression.Operand;
if (unaryExpression.Type != typeof(object))
{
convertedType = unaryExpression.Type;
}
}

if (source is EntityShaperExpression entityShaper)
{
var entityType = entityShaper.EntityType;
if (convertedType != null)
{
entityType = entityType.RootType().GetDerivedTypesInclusive()
.FirstOrDefault(et => et.ClrType == convertedType);
}

if (entityType != null)
{
var property = entityType.FindProperty(propertyName);

return BindProperty(entityShaper, property);
}
}

throw new InvalidOperationException();
return BindProperty(source, propertyName);
}

if (methodCallExpression.Method.DeclaringType == typeof(Queryable))
Expand Down
30 changes: 15 additions & 15 deletions test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ from g2 in gs
select g1.LeaderNickname != null ? g2.LeaderNickname : (string)null);
}

[ConditionalTheory(Skip = "issue #15848")]
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Select_null_propagation_negative3(bool isAsync)
{
Expand All @@ -1198,7 +1198,7 @@ orderby Maybe(g2, () => g2.Nickname)
assertOrder: true);
}

[ConditionalTheory(Skip = "issue #15848")]
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Select_null_propagation_negative4(bool isAsync)
{
Expand All @@ -1217,7 +1217,7 @@ orderby Maybe(g2, () => g2.Nickname)
assertOrder: true);
}

[ConditionalTheory(Skip = "issue #15848")]
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Select_null_propagation_negative5(bool isAsync)
{
Expand Down Expand Up @@ -3529,7 +3529,7 @@ private static IEnumerable<Gear> Veterans(IEnumerable<Gear> gears)
return gears.Where(g => g.Nickname == "Marcus" || g.Nickname == "Dom" || g.Nickname == "Cole Train" || g.Nickname == "Baird");
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Member_access_on_derived_entity_using_cast()
{
using (var ctx = CreateContext())
Expand All @@ -3553,7 +3553,7 @@ where f is LocustHorde
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Member_access_on_derived_materialized_entity_using_cast()
{
using (var ctx = CreateContext())
Expand All @@ -3577,7 +3577,7 @@ orderby f.Name
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Member_access_on_derived_entity_using_cast_and_let()
{
using (var ctx = CreateContext())
Expand Down Expand Up @@ -4067,7 +4067,7 @@ public virtual void Optional_navigation_with_collection_composite_key()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Select_null_conditional_with_inheritance()
{
using (var context = CreateContext())
Expand All @@ -4083,7 +4083,7 @@ public virtual void Select_null_conditional_with_inheritance()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Select_null_conditional_with_inheritance_negative()
{
using (var context = CreateContext())
Expand Down Expand Up @@ -5939,7 +5939,7 @@ join g in gs on o.FullName equals g.FullName into grouping
elementAsserter: (e, a) => CollectionAsserter<string>(elementSorter: ee => ee)(e.Collection, a.Collection));
}

[ConditionalTheory(Skip = "issue #15848")]
[ConditionalTheory(Skip = "Issue#15611")]
[MemberData(nameof(IsAsyncData))]
public virtual Task Outer_parameter_in_group_join_with_DefaultIfEmpty(bool isAsync)
{
Expand Down Expand Up @@ -6025,7 +6025,7 @@ public virtual Task Order_by_entity_qsre(bool isAsync)
assertOrder: true);
}

[ConditionalTheory(Skip = "issue #15848")]
[ConditionalTheory(Skip = "Issue#15939")]
[MemberData(nameof(IsAsyncData))]
public virtual Task Order_by_entity_qsre_with_inheritance(bool isAsync)
{
Expand Down Expand Up @@ -7430,7 +7430,7 @@ public virtual void OfTypeNav3()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact(Skip = "Issue#15964")]
public virtual void Nav_rewrite_Distinct_with_convert()
{
using (var ctx = CreateContext())
Expand All @@ -7440,7 +7440,7 @@ public virtual void Nav_rewrite_Distinct_with_convert()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact(Skip = "Issue#15964")]
public virtual void Nav_rewrite_Distinct_with_convert_anonymous()
{
using (var ctx = CreateContext())
Expand All @@ -7460,7 +7460,7 @@ public virtual void Nav_rewrite_with_convert1()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Nav_rewrite_with_convert2()
{
using (var ctx = CreateContext())
Expand All @@ -7470,7 +7470,7 @@ public virtual void Nav_rewrite_with_convert2()
}
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Nav_rewrite_with_convert3()
{
using (var ctx = CreateContext())
Expand All @@ -7489,7 +7489,7 @@ public virtual Task Where_contains_on_navigation_with_composite_keys(bool isAsyn
(gs, cs) => gs.Where(g => cs.Any(c => c.BornGears.Contains(g))));
}

[ConditionalFact(Skip = "issue #15848")]
[ConditionalFact]
public virtual void Project_derivied_entity_with_convert_to_parent()
{
using (var ctx = CreateContext())
Expand Down

0 comments on commit 21865b6

Please sign in to comment.