Skip to content

Commit

Permalink
Query: Add ability for translation pipeline to translate property acc…
Browse files Browse the repository at this point in the history
…ess over a subquery

This removes need to run subquery member pushdown after entity equality
Part of #20164
Part of #18923

Also improves Cosmos recursive binding over embedded navigations
  • Loading branch information
smitpatel committed Mar 28, 2020
1 parent bed9641 commit 8771406
Show file tree
Hide file tree
Showing 8 changed files with 1,010 additions and 984 deletions.
506 changes: 250 additions & 256 deletions src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

663 changes: 340 additions & 323 deletions src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -45,43 +45,36 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
Check.NotNull(binaryExpression, nameof(binaryExpression));

var visitedExpression = (SqlExpression)base.VisitBinary(binaryExpression);

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

return visitedExpression is SqlBinaryExpression sqlBinary
&& _arithmeticOperatorTypes.Contains(sqlBinary.OperatorType)
&& (_dateTimeDataTypes.Contains(GetProviderType(sqlBinary.Left))
|| _dateTimeDataTypes.Contains(GetProviderType(sqlBinary.Right)))
? null
: visitedExpression;
return !(base.VisitBinary(binaryExpression) is SqlExpression visitedExpression)
? (Expression)null
: (Expression)(visitedExpression is SqlBinaryExpression sqlBinary
&& _arithmeticOperatorTypes.Contains(sqlBinary.OperatorType)
&& (_dateTimeDataTypes.Contains(GetProviderType(sqlBinary.Left))
|| _dateTimeDataTypes.Contains(GetProviderType(sqlBinary.Right)))
? null
: visitedExpression);
}

protected override Expression VisitUnary(UnaryExpression unaryExpression)
{
if (unaryExpression.NodeType == ExpressionType.ArrayLength
&& unaryExpression.Operand.Type == typeof(byte[]))
{
var sqlExpression = base.Visit(unaryExpression.Operand) as SqlExpression;

if (sqlExpression == null)
if (!(base.Visit(unaryExpression.Operand) is SqlExpression sqlExpression))
{
return null;
}

var isBinaryMaxDataType = GetProviderType(sqlExpression) == "varbinary(max)" || sqlExpression is SqlParameterExpression;
var dataLengthSqlFunction = SqlExpressionFactory.Function(
var dataLengthSqlFunction = Dependencies.SqlExpressionFactory.Function(
"DATALENGTH",
new[] { sqlExpression },
nullable: true,
argumentsPropagateNullability: new bool[] { true },
isBinaryMaxDataType ? typeof(long) : typeof(int));

return isBinaryMaxDataType
? (Expression)SqlExpressionFactory.Convert(dataLengthSqlFunction, typeof(int))
? (Expression)Dependencies.SqlExpressionFactory.Convert(dataLengthSqlFunction, typeof(int))
: dataLengthSqlFunction;
}

Expand All @@ -96,18 +89,15 @@ public override SqlExpression TranslateLongCount(Expression expression = null)
return null;
}

return SqlExpressionFactory.ApplyDefaultTypeMapping(
SqlExpressionFactory.Function(
return Dependencies.SqlExpressionFactory.ApplyDefaultTypeMapping(
Dependencies.SqlExpressionFactory.Function(
"COUNT_BIG",
new[] { SqlExpressionFactory.Fragment("*") },
new[] { Dependencies.SqlExpressionFactory.Fragment("*") },
nullable: false,
argumentsPropagateNullability: new[] { false },
typeof(long)));
}

private static string GetProviderType(SqlExpression expression)
{
return expression.TypeMapping?.StoreType;
}
private static string GetProviderType(SqlExpression expression) => expression.TypeMapping?.StoreType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression)
&& unaryExpression.Operand.Type == typeof(byte[]))
{
return base.Visit(unaryExpression.Operand) is SqlExpression sqlExpression
? SqlExpressionFactory.Function(
? Dependencies.SqlExpressionFactory.Function(
"length",
new[] { sqlExpression },
nullable: true,
Expand Down Expand Up @@ -127,9 +127,7 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
Check.NotNull(binaryExpression, nameof(binaryExpression));

var visitedExpression = (SqlExpression)base.VisitBinary(binaryExpression);

if (visitedExpression == null)
if (!(base.VisitBinary(binaryExpression) is SqlExpression visitedExpression))
{
return null;
}
Expand All @@ -140,7 +138,7 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
&& (_functionModuloTypes.Contains(GetProviderType(sqlBinary.Left))
|| _functionModuloTypes.Contains(GetProviderType(sqlBinary.Right))))
{
return SqlExpressionFactory.Function(
return Dependencies.SqlExpressionFactory.Function(
"ef_mod",
new[] { sqlBinary.Left, sqlBinary.Right },
nullable: true,
Expand Down Expand Up @@ -242,20 +240,20 @@ private static bool AttemptDecimalCompare(SqlBinaryExpression sqlBinary) =>

private Expression DoDecimalCompare(SqlExpression visitedExpression, ExpressionType op, SqlExpression left, SqlExpression right)
{
var actual = SqlExpressionFactory.Function(
var actual = Dependencies.SqlExpressionFactory.Function(
name: "ef_compare",
new[] { left, right },
nullable: true,
new[] { true, true },
typeof(int));
var oracle = SqlExpressionFactory.Constant(value: 0);
var oracle = Dependencies.SqlExpressionFactory.Constant(value: 0);

return op switch
{
ExpressionType.GreaterThan => SqlExpressionFactory.GreaterThan(left: actual, right: oracle),
ExpressionType.GreaterThanOrEqual => SqlExpressionFactory.GreaterThanOrEqual(left: actual, right: oracle),
ExpressionType.LessThan => SqlExpressionFactory.LessThan(left: actual, right: oracle),
ExpressionType.LessThanOrEqual => SqlExpressionFactory.LessThanOrEqual(left: actual, right: oracle),
ExpressionType.GreaterThan => Dependencies.SqlExpressionFactory.GreaterThan(left: actual, right: oracle),
ExpressionType.GreaterThanOrEqual => Dependencies.SqlExpressionFactory.GreaterThanOrEqual(left: actual, right: oracle),
ExpressionType.LessThan => Dependencies.SqlExpressionFactory.LessThan(left: actual, right: oracle),
ExpressionType.LessThanOrEqual => Dependencies.SqlExpressionFactory.LessThanOrEqual(left: actual, right: oracle),
_ => visitedExpression
};
}
Expand Down
10 changes: 6 additions & 4 deletions src/EFCore/Properties/CoreStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/EFCore/Properties/CoreStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1341,8 +1341,8 @@
<data name="UnsupportedBinaryOperator" xml:space="preserve">
<value>Unsupported Binary operator type specified.</value>
</data>
<data name="EFPropertyCalledWithWrongPropertyName" xml:space="preserve">
<value>EF.Property called with wrong property name.</value>
<data name="QueryUnableToTranslateEFProperty" xml:space="preserve">
<value>Translation of '{expression}' failed. Either source is not an entity type or the specified property does not exist on the entity type.</value>
</data>
<data name="InvalidStateEncountered" xml:space="preserve">
<value>Invalid {state} encountered.</value>
Expand Down
1 change: 0 additions & 1 deletion src/EFCore/Query/EntityShaperExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;

Expand Down

0 comments on commit 8771406

Please sign in to comment.