Skip to content

Commit

Permalink
Query: Lift subqueries projecting single scalar values
Browse files Browse the repository at this point in the history
Resolves #15705
  • Loading branch information
smitpatel committed May 15, 2019
1 parent 1eba3fe commit 20cf7c8
Show file tree
Hide file tree
Showing 91 changed files with 1,203 additions and 805 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public override EntityQueryableTranslator Create(QueryCompilationContext2 queryC

public class CosmosQueryableMethodTranslatingExpressionVisitorFactory : IQueryableMethodTranslatingExpressionVisitorFactory
{
public QueryableMethodTranslatingExpressionVisitor Create(QueryCompilationContext2 queryCompilationContext)
public QueryableMethodTranslatingExpressionVisitor Create(IModel model)
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public override Expression Visit(Expression expression)
&& methodCall.Arguments[0] is EntityShaperExpression entityShaperExpression
&& entityShaperExpression.EntityType.GetProperties().Count() == newArrayExpression.Expressions.Count)
{
VerifyQueryExpression(entityShaperExpression.ValueBufferExpression);

_projectionMapping[_projectionMembers.Peek()]
= _queryExpression.GetProjectionExpression(
entityShaperExpression.ValueBufferExpression.ProjectionMember);
Expand All @@ -77,7 +79,7 @@ public override Expression Visit(Expression expression)

_projectionMapping[_projectionMembers.Peek()] = translation;

return new ProjectionBindingExpression(_projectionMembers.Peek(), expression.Type);
return new ProjectionBindingExpression(_queryExpression, _projectionMembers.Peek(), expression.Type);
}

return base.Visit(expression);
Expand All @@ -87,12 +89,14 @@ protected override Expression VisitExtension(Expression extensionExpression)
{
if (extensionExpression is EntityShaperExpression entityShaperExpression)
{
VerifyQueryExpression(entityShaperExpression.ValueBufferExpression);

_projectionMapping[_projectionMembers.Peek()]
= _queryExpression.GetProjectionExpression(
entityShaperExpression.ValueBufferExpression.ProjectionMember);

return entityShaperExpression.Update(
new ProjectionBindingExpression(_projectionMembers.Peek(), typeof(ValueBuffer)));
new ProjectionBindingExpression(_queryExpression, _projectionMembers.Peek(), typeof(ValueBuffer)));
}

throw new InvalidOperationException();
Expand Down Expand Up @@ -132,5 +136,14 @@ protected override Expression VisitMemberInit(MemberInitExpression memberInitExp

return memberInitExpression.Update(newExpression, newBindings);
}

// TODO: Debugging
private void VerifyQueryExpression(ProjectionBindingExpression projectionBindingExpression)
{
if (projectionBindingExpression.QueryExpression != _queryExpression)
{
throw new InvalidOperationException();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public Expression GetSingleScalarProjection()
_projectionMapping.Clear();
_projectionMapping[new ProjectionMember()] = _valueBufferSlots[0];

return new ProjectionBindingExpression(new ProjectionMember(), ServerQueryExpression.Type);
return new ProjectionBindingExpression(this, new ProjectionMember(), ServerQueryExpression.Type);
}

public Expression BindProperty(Expression projectionExpression, IProperty property)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class InMemoryQueryableMethodTranslatingExpressionVisitorFactory : IQueryableMethodTranslatingExpressionVisitorFactory
{
public QueryableMethodTranslatingExpressionVisitor Create(QueryCompilationContext2 queryCompilationContext)
public QueryableMethodTranslatingExpressionVisitor Create(IModel model)
{
return new InMemoryQueryableMethodTranslatingExpressionVisitor();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public InMemoryShapedQueryExpression(IEntityType entityType)
QueryExpression = new InMemoryQueryExpression(entityType);
ShaperExpression = new EntityShaperExpression(
entityType,
new ProjectionBindingExpression(new ProjectionMember(), typeof(ValueBuffer)),
new ProjectionBindingExpression(
QueryExpression,
new ProjectionMember(), typeof(ValueBuffer)),
false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline
{
public interface IRelationalSqlTranslatingExpressionVisitorFactory
{
RelationalSqlTranslatingExpressionVisitor Create(IModel model);
RelationalSqlTranslatingExpressionVisitor Create(
IModel model,
IQueryableMethodTranslatingExpressionVisitorFactory queryableMethodTranslatingExpressionVisitorFactory);
}
}
36 changes: 36 additions & 0 deletions src/EFCore.Relational/Query/Pipeline/NullableValueTranslator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions;

namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline
{
public class NullableMemberTranslator : IMemberTranslator
{
private readonly ISqlExpressionFactory _sqlExpressionFactory;

public NullableMemberTranslator(ISqlExpressionFactory sqlExpressionFactory)
{
_sqlExpressionFactory = sqlExpressionFactory;
}

public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType)
{
if (member.DeclaringType.IsNullableType())
{
switch (member.Name)
{
case nameof(Nullable<int>.Value):
return instance;

case nameof(Nullable<int>.HasValue):
return _sqlExpressionFactory.IsNotNull(instance);
}
}

return null;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -635,5 +635,17 @@ protected override Expression VisitLeftJoin(LeftJoinExpression leftJoinExpressio

return leftJoinExpression;
}

protected override Expression VisitSubSelect(SubSelectExpression subSelectExpression)
{
_relationalCommandBuilder.Append("(");
using (_relationalCommandBuilder.Indent())
{
Visit(subSelectExpression.Subquery);
}
_relationalCommandBuilder.Append(")");

return subSelectExpression;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ public class RelationalMemberTranslatorProvider : IMemberTranslatorProvider
private readonly List<IMemberTranslator> _plugins = new List<IMemberTranslator>();
private readonly List<IMemberTranslator> _translators = new List<IMemberTranslator>();

public RelationalMemberTranslatorProvider(IEnumerable<IMemberTranslatorPlugin> plugins)
public RelationalMemberTranslatorProvider(ISqlExpressionFactory sqlExpressionFactory,
IEnumerable<IMemberTranslatorPlugin> plugins)
{
_plugins.AddRange(plugins.SelectMany(p => p.Translators));
_translators
.AddRange(
new[]
{
new NullableValueTranslator(),
new NullableMemberTranslator(sqlExpressionFactory),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,20 @@ public override Expression Visit(Expression expression)
&& methodCall.Arguments[0] is EntityShaperExpression entityShaperExpression
&& entityShaperExpression.EntityType.GetProperties().Count() == newArrayExpression.Expressions.Count)
{
VerifySelectExpression(entityShaperExpression.ValueBufferExpression);

_projectionMapping[_projectionMembers.Peek()]
= _selectExpression.GetProjectionExpression(
entityShaperExpression.ValueBufferExpression.ProjectionMember);

return new EntityValuesExpression(entityShaperExpression.EntityType, entityShaperExpression.ValueBufferExpression);
}

var translation = _sqlTranslator.Translate(_selectExpression, expression);
var translation = _sqlTranslator.Translate(expression);

_projectionMapping[_projectionMembers.Peek()] = translation ?? throw new InvalidOperationException();

return new ProjectionBindingExpression(_projectionMembers.Peek(), expression.Type);
return new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type);
}

return base.Visit(expression);
Expand All @@ -97,12 +99,14 @@ protected override Expression VisitExtension(Expression extensionExpression)
{
if (extensionExpression is EntityShaperExpression entityShaperExpression)
{
VerifySelectExpression(entityShaperExpression.ValueBufferExpression);

_projectionMapping[_projectionMembers.Peek()]
= _selectExpression.GetProjectionExpression(
entityShaperExpression.ValueBufferExpression.ProjectionMember);

return entityShaperExpression.Update(
new ProjectionBindingExpression(_projectionMembers.Peek(), typeof(ValueBuffer)));
new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer)));
}

throw new InvalidOperationException();
Expand Down Expand Up @@ -142,5 +146,14 @@ protected override Expression VisitMemberInit(MemberInitExpression memberInitExp

return memberInitExpression.Update(newExpression, newBindings);
}

// TODO: Debugging
private void VerifySelectExpression(ProjectionBindingExpression projectionBindingExpression)
{
if (projectionBindingExpression.QueryExpression != _selectExpression)
{
throw new InvalidOperationException();
}
}
}
}
Loading

0 comments on commit 20cf7c8

Please sign in to comment.