Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query: Remove AnonymousObject #20644

Merged
merged 1 commit into from
Apr 16, 2020
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 @@ -6,7 +6,7 @@
using System.Reflection;
using JetBrains.Annotations;

namespace Microsoft.EntityFrameworkCore.Query.Internal
namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
Check.NotNull(binaryExpression, nameof(binaryExpression));

if (binaryExpression.Left.Type == typeof(object[])
&& binaryExpression.Left is NewArrayExpression
&& binaryExpression.NodeType == ExpressionType.Equal)
{
return Visit(ConvertObjectArrayEqualityComparison(binaryExpression));
}

var newLeft = Visit(binaryExpression.Left);
var newRight = Visit(binaryExpression.Right);

Expand Down Expand Up @@ -1098,6 +1105,38 @@ private static bool CanEvaluate(Expression expression)
}
}

private static Expression ConvertObjectArrayEqualityComparison(BinaryExpression binaryExpression)
{
var leftExpressions = ((NewArrayExpression)binaryExpression.Left).Expressions;
var rightExpressions = ((NewArrayExpression)binaryExpression.Right).Expressions;

return leftExpressions.Zip(
rightExpressions,
(l, r) =>
{
l = RemoveObjectConvert(l);
r = RemoveObjectConvert(r);
if (l.Type.IsNullableType())
{
r = r.Type.IsNullableType() ? r : Expression.Convert(r, l.Type);
}
else if (r.Type.IsNullableType())
{
l = l.Type.IsNullableType() ? l : Expression.Convert(l, r.Type);
}

return Expression.Equal(l, r);
})
.Aggregate((a, b) => Expression.AndAlso(a, b));

static Expression RemoveObjectConvert(Expression expression)
=> expression is UnaryExpression unaryExpression
&& expression.Type == typeof(object)
&& expression.NodeType == ExpressionType.Convert
? unaryExpression.Operand
: expression;
}

private static bool IsNullConstantExpression(Expression expression)
=> expression is ConstantExpression constantExpression && constantExpression.Value == null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.EntityFrameworkCore.InMemory.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;

Expand Down Expand Up @@ -457,6 +456,7 @@ private static (Expression, Expression) DecomposeJoinCondition(Expression joinCo
: (CreateAnonymousObject(leftExpressions), CreateAnonymousObject(rightExpressions))
: (null, null);

// InMemory joins need to use AnonymousObject to perform correct key comparison for server side joins
static Expression CreateAnonymousObject(List<Expression> expressions)
=> Expression.New(
AnonymousObject.AnonymousObjectCtor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,7 @@ private SqlExpression CreateJoinPredicate(
var outerKey = RemapLambdaBody(outer, outerKeySelector);
var innerKey = RemapLambdaBody(inner, innerKeySelector);

if (outerKey is NewExpression outerNew
&& outerNew.Type != typeof(AnonymousObject))
if (outerKey is NewExpression outerNew)
{
var innerNew = (NewExpression)innerKey;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Utilities;

Expand Down Expand Up @@ -237,10 +236,11 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
Check.NotNull(binaryExpression, nameof(binaryExpression));

if (binaryExpression.Left.Type == typeof(AnonymousObject)
if (binaryExpression.Left.Type == typeof(object[])
&& binaryExpression.Left is NewArrayExpression
&& binaryExpression.NodeType == ExpressionType.Equal)
{
return Visit(ConvertAnonymousObjectEqualityComparison(binaryExpression));
return Visit(ConvertObjectArrayEqualityComparison(binaryExpression));
}

var left = TryRemoveImplicitConvert(binaryExpression.Left);
Expand Down Expand Up @@ -768,10 +768,10 @@ private static Expression TryRemoveImplicitConvert(Expression expression)
return expression;
}

private static Expression ConvertAnonymousObjectEqualityComparison(BinaryExpression binaryExpression)
private static Expression ConvertObjectArrayEqualityComparison(BinaryExpression binaryExpression)
{
var leftExpressions = ((NewArrayExpression)((NewExpression)binaryExpression.Left).Arguments[0]).Expressions;
var rightExpressions = ((NewArrayExpression)((NewExpression)binaryExpression.Right).Arguments[0]).Expressions;
var leftExpressions = ((NewArrayExpression)binaryExpression.Left).Expressions;
var rightExpressions = ((NewArrayExpression)binaryExpression.Right).Expressions;

return leftExpressions.Zip(
rightExpressions,
Expand Down
12 changes: 5 additions & 7 deletions src/EFCore/Infrastructure/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,11 @@ public static Expression CreateKeyValueReadExpression(
bool makeNullable = false)
=> properties.Count == 1
? target.CreateEFPropertyExpression(properties[0], makeNullable)
: Expression.New(
AnonymousObject.AnonymousObjectCtor,
Expression.NewArrayInit(
typeof(object),
properties
.Select(p => Expression.Convert(target.CreateEFPropertyExpression(p, makeNullable), typeof(object)))
.Cast<Expression>()));
: Expression.NewArrayInit(
typeof(object),
properties
.Select(p => Expression.Convert(target.CreateEFPropertyExpression(p, makeNullable), typeof(object)))
.Cast<Expression>());

/// <summary>
/// <para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,7 @@ protected Expression ExpandNavigation(
// This is intentionally deferred to be applied to innerSource.Source
// Since outerKey's reference could change if a reference navigation is expanded afterwards
var predicateBody = Expression.AndAlso(
outerKey is NewExpression newExpression
&& newExpression.Arguments[0] is NewArrayExpression newArrayExpression
outerKey is NewArrayExpression newArrayExpression
? newArrayExpression.Expressions
.Select(e =>
{
Expand Down