From 6774c702105e64f90bcbf909ea3d49e268225759 Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Tue, 15 Oct 2019 18:11:39 -0700 Subject: [PATCH] Query: Skip updating NewExpression without ctor Scenario: NewExpression of struct type which does not have any ctor arguments (so new DateTime()). New DateTime(2019, 12, 11) still has ctor so it works fine. Struct type could be user defined or system defined. Root cause: When calling NewExpression.Update the way checking if arguments are changed is different in .NET Framework & Core. Since arguments are 0, it should not need to be updated. .NET Core identifies this correctly and does not cause regeneration avoiding the exception. --- ...nMemoryExpressionTranslatingExpressionVisitor.cs | 6 ++++++ .../InMemoryProjectionBindingExpressionVisitor.cs | 6 ++++++ .../Query/Internal/InMemoryQueryExpression.cs | 6 ++++++ ...ryQueryableMethodTranslatingExpressionVisitor.cs | 6 ++++++ .../RelationalProjectionBindingExpressionVisitor.cs | 6 ++++++ ...alQueryableMethodTranslatingExpressionVisitor.cs | 6 ++++++ .../EntityEqualityRewritingExpressionVisitor.cs | 6 ++++++ ...ExpandingExpressionVisitor.ExpressionVisitors.cs | 13 +++++++++++++ .../NavigationExpandingExpressionVisitor.cs | 6 ++++++ 9 files changed, 61 insertions(+) diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs index 09b47725b37..f56031cbf3c 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs @@ -483,6 +483,12 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression typeBinaryExp protected override Expression VisitNew(NewExpression newExpression) { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + var newArguments = new List(); foreach (var argument in newExpression.Arguments) { diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs index 51bdb1e2ac5..7e86283543f 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs @@ -225,6 +225,12 @@ protected override Expression VisitExtension(Expression extensionExpression) protected override Expression VisitNew(NewExpression newExpression) { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + if (newExpression.Arguments.Count == 0) { return newExpression; diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs index ba334e2d262..504c13d1e01 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs @@ -399,6 +399,12 @@ private Expression GetGroupingKey(Expression key, List groupingExpre switch (key) { case NewExpression newExpression: + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + var arguments = new Expression[newExpression.Arguments.Count]; for (var i = 0; i < arguments.Length; i++) { diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index 9394da76a61..23fc632c57a 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -283,6 +283,12 @@ private Expression TranslateGroupingKey(Expression expression) switch (expression) { case NewExpression newExpression: + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + if (newExpression.Arguments.Count == 0) { return newExpression; diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs index 26f6edcf747..2fa2b8f8f49 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs @@ -225,6 +225,12 @@ protected override Expression VisitExtension(Expression extensionExpression) protected override Expression VisitNew(NewExpression newExpression) { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + if (newExpression.Arguments.Count == 0) { return newExpression; diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 9b1087170c4..61ac1d2b177 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -345,6 +345,12 @@ private Expression TranslateGroupingKey(Expression expression) switch (expression) { case NewExpression newExpression: + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + if (newExpression.Arguments.Count == 0) { return newExpression; diff --git a/src/EFCore/Query/Internal/EntityEqualityRewritingExpressionVisitor.cs b/src/EFCore/Query/Internal/EntityEqualityRewritingExpressionVisitor.cs index 77280a56cba..917e59753e9 100644 --- a/src/EFCore/Query/Internal/EntityEqualityRewritingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/EntityEqualityRewritingExpressionVisitor.cs @@ -58,6 +58,12 @@ protected override Expression VisitConstant(ConstantExpression constantExpressio protected override Expression VisitNew(NewExpression newExpression) { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + var visitedArgs = Visit(newExpression.Arguments); var visitedExpression = newExpression.Update(visitedArgs.Select(Unwrap)); diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index b0d0a08b2cb..c478b80504d 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -366,6 +366,12 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp protected override Expression VisitNew(NewExpression newExpression) { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return newExpression; + } + var arguments = new Expression[newExpression.Arguments.Count]; for (var i = 0; i < newExpression.Arguments.Count; i++) { @@ -382,6 +388,13 @@ private bool ReconstructAnonymousType(Expression currentRoot, NewExpression newE { replacement = null; var changed = false; + + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return false; + } + if (newExpression.Arguments.Count > 0 && newExpression.Members == null) { diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs index 78923b7b1d6..70d1b8d804f 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs @@ -1235,6 +1235,12 @@ private Expression SnapshotExpression(Expression selector) case NewExpression newExpression: { + // For .NET Framework only. If ctor is null that means the type is struct and has no ctor args. + if (newExpression.Constructor == null) + { + return Expression.Default(newExpression.Type); + } + var arguments = new Expression[newExpression.Arguments.Count]; for (var i = 0; i < newExpression.Arguments.Count; i++) {