From b5e9b6d5f339d5d790a80474ef88eda671d9d080 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 12 Oct 2022 14:21:40 +0200 Subject: [PATCH 1/6] Fix issue with uwrapped Parameters --- .../Test01Issue152.cs | 74 ++++++++++ .../OptimizeExpressionVisitor.cs | 135 +++++++++++------- 2 files changed, 157 insertions(+), 52 deletions(-) create mode 100644 src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs diff --git a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs new file mode 100644 index 0000000..292afdf --- /dev/null +++ b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs @@ -0,0 +1,74 @@ +using System.Linq; +using System.Net.Mail; +using DelegateDecompiler.EntityFramework.Tests.EfItems; +using DelegateDecompiler.EntityFramework.Tests.EfItems.Abstracts; +using DelegateDecompiler.EntityFramework.Tests.Helpers; +using NUnit.Framework; + +namespace DelegateDecompiler.EntityFramework.Tests.TestGroup90AdditionalFeatures +{ + public static class EfTestDbContextExtensions + { + [Computed] + public static int GetFirstChildIdByParent(this EfTestDbContext context, int parentId) + { + return context.EfChildren.Where(e => e.EfParentId == parentId).Select(e => e.EfChildId).FirstOrDefault(); + } + } + + class Test01Issue152 + { + private ClassEnvironment classEnv; + + [OneTimeSetUp] + public void SetUpFixture() + { + classEnv = new ClassEnvironment(); + } + + class ParentIdWithFirstChildId + { + public int ParentId { get; set; } + public int FirstChildId { get; set; } + + public override bool Equals(object obj) + { + return (obj as ParentIdWithFirstChildId)?.ParentId == ParentId && (obj as ParentIdWithFirstChildId)?.FirstChildId == FirstChildId; + } + + public override int GetHashCode() + { + return ParentId * 131 + FirstChildId; + } + } + + [Test] +#if EF_CORE && !EF_CORE3 && !EF_CORE5 + [Ignore("Not natively supported in EF_CORE < 3")] +#endif + public void TestSubqueryAsContextExtensionMethod() + { + using (var env = new MethodEnvironment(classEnv)) + { + //SETUP + var linq = env.Db.EfParents.Select(x => new ParentIdWithFirstChildId() + { + ParentId = x.EfParentId, + FirstChildId = env.Db.EfChildren.Where(e => e.EfParentId == x.EfParentId).Select(e => e.EfChildId).FirstOrDefault() + }).ToList(); + + //ATTEMPT + env.AboutToUseDelegateDecompiler(); + var query = env.Db.EfParents.Select(x => new ParentIdWithFirstChildId() + { + ParentId = x.EfParentId, + FirstChildId = env.Db.GetFirstChildIdByParent(x.EfParentId) + }).Decompile(); + var dd = query.ToList(); + + //VERIFY + env.CompareAndLogList(linq, dd); + } + } + } +} \ No newline at end of file diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index 106a388..bf91901 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -51,7 +51,7 @@ protected override Expression VisitConditional(ConditionalExpression node) if (TryConvert1(test, ifTrueBinary, out result)) return result; } - + var testBinary = test as BinaryExpression; var ifTrueConstant = ifTrue as ConstantExpression; var ifFalseConstant = ifFalse as ConstantExpression; @@ -209,16 +209,16 @@ private static bool TryConvert1(Expression hasValue, BinaryExpression getValueOr static Expression ConvertToNullable(Expression expression) { - if (!expression.Type.IsValueType || expression.Type.IsNullableType()) return expression; + if (!expression.Type.IsValueType || expression.Type.IsNullableType()) return expression; - var operand = expression.NodeType == ExpressionType.Convert - ? ((UnaryExpression) expression).Operand - : expression; + var operand = expression.NodeType == ExpressionType.Convert + ? ((UnaryExpression) expression).Operand + : expression; - return Expression.Convert(operand, typeof(Nullable<>).MakeGenericType(expression.Type)); - } + return Expression.Convert(operand, typeof(Nullable<>).MakeGenericType(expression.Type)); + } - static Expression UnwrapConvertToNullable(Expression expression) + static Expression UnwrapConvertToNullable(Expression expression) { var unary = expression as UnaryExpression; if (unary != null && expression.NodeType == ExpressionType.Convert && expression.Type.IsNullableType()) @@ -233,11 +233,11 @@ static bool ExtractNullableArgument(Expression hasValue, Expression getValueOrDe MemberExpression memberExpression; if (IsHasValue(hasValue, out memberExpression)) { - expression = new GetValueOrDefaultRemover(memberExpression.Expression).Visit(getValueOrDefault); + expression = new GetValueOrDefaultRemover(memberExpression.Expression).Visit(getValueOrDefault); if (expression != getValueOrDefault) return true; } - + expression = null; return false; } @@ -252,12 +252,12 @@ static bool IsCoalesce(Expression hasValue, Expression getValueOrDefault, out Ex if (expression == callExpression.Object) return true; } - + expression = null; return false; } - static bool IsHasValue(Expression expression, out MemberExpression property) + static bool IsHasValue(Expression expression, out MemberExpression property) { property = expression as MemberExpression; return property != null && property.Member.Name == "HasValue" && property.Expression != null && property.Expression.Type.IsNullableType(); @@ -324,7 +324,7 @@ left is MethodCallExpression expression && protected override Expression VisitUnary(UnaryExpression node) { - if (node.NodeType == ExpressionType.Not && + if (node.NodeType == ExpressionType.Not && node.Operand is BinaryExpression binary && Invert(ref binary)) { @@ -350,40 +350,40 @@ static bool Invert(ref BinaryExpression expression) switch (expression.NodeType) { case ExpressionType.Equal: - { - expression = Expression.NotEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.NotEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.NotEqual: - { - expression = Expression.Equal(expression.Left, expression.Right); - return true; - } + { + expression = Expression.Equal(expression.Left, expression.Right); + return true; + } case ExpressionType.LessThan: - { - expression = Expression.GreaterThanOrEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.GreaterThanOrEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.LessThanOrEqual: - { - expression = Expression.GreaterThan(expression.Left, expression.Right); - return true; - } + { + expression = Expression.GreaterThan(expression.Left, expression.Right); + return true; + } case ExpressionType.GreaterThan: - { - expression = Expression.LessThanOrEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.LessThanOrEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.GreaterThanOrEqual: - { - expression = Expression.LessThan(expression.Left, expression.Right); - return true; - } + { + expression = Expression.LessThan(expression.Left, expression.Right); + return true; + } } return false; } - class GetValueOrDefaultRemover :ExpressionVisitor + class GetValueOrDefaultRemover : ExpressionVisitor { readonly Expression expected; @@ -417,19 +417,19 @@ protected override Expression VisitBinary(BinaryExpression node) return node.Update(left, conversion, right); } - protected override Expression VisitUnary(UnaryExpression node) - { - var before = node; - var operand = Visit(node.Operand); + protected override Expression VisitUnary(UnaryExpression node) + { + var before = node; + var operand = Visit(node.Operand); - if (operand != before.Operand) - { - operand = ConvertToNullable(operand); - } + if (operand != before.Operand) + { + operand = ConvertToNullable(operand); + } - return before.Update(operand); - } - } + return before.Update(operand); + } + } class GetValueOrDefaultToCoalesceConverter : ExpressionVisitor { @@ -446,19 +446,20 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return base.VisitMethodCall(node); } } - + class LinqExpressionUnwrapper : ExpressionVisitor { public static Expression Unwrap(Expression expression) { var visit = new LinqExpressionUnwrapper().Visit(expression); var func = Expression.Lambda>(visit).Compile(); - return Expression.Quote(func()); + var output = UnwrappedParameterMerger.Merge(func()); + return Expression.Quote(output); } protected override Expression VisitMethodCall(MethodCallExpression node) { - if (node.Method.Name == nameof(Expression.Constant) && + if (node.Method.Name == nameof(Expression.Constant) && node.Method.DeclaringType == typeof(Expression) && node.Arguments[0] is Expression parameter) { @@ -469,6 +470,36 @@ protected override Expression VisitMethodCall(MethodCallExpression node) } } + class UnwrappedParameterMerger : ExpressionVisitor + { + private Dictionary parameters = new Dictionary(); + private LambdaExpression lambda; + + public static Expression Merge(Expression expression) + { + var resolver = new UnwrappedParameterMerger(); + resolver.lambda = expression as LambdaExpression; + return resolver.Visit(resolver.lambda); + } + + protected override Expression VisitParameter(ParameterExpression node) + { + if (!parameters.TryGetValue(node.Name, out ParameterExpression parameter)) + { + for (var i = 0; i < lambda.Parameters.Count; i++) + { + if (node.Name == lambda.Parameters[i].Name) + { + node = lambda.Parameters[i]; + parameters.Add(node.Name, node); + break; + } + } + } + return node; + } + } + public static Expression Optimize(Expression expression) { return new GetValueOrDefaultToCoalesceConverter().Visit(new OptimizeExpressionVisitor().Visit(expression)); From cb0be51cb30055bef5a69bd6a4c8029e0d44abf7 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 13 Oct 2022 14:14:07 +1300 Subject: [PATCH 2/6] Revert whitespace chanegs --- .../OptimizeExpressionVisitor.cs | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index 796d062..400927d 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -51,7 +51,7 @@ protected override Expression VisitConditional(ConditionalExpression node) if (TryConvert1(test, ifTrueBinary, out result)) return result; } - + var testBinary = test as BinaryExpression; var ifTrueConstant = ifTrue as ConstantExpression; var ifFalseConstant = ifFalse as ConstantExpression; @@ -209,16 +209,16 @@ private static bool TryConvert1(Expression hasValue, BinaryExpression getValueOr static Expression ConvertToNullable(Expression expression) { - if (!expression.Type.IsValueType || expression.Type.IsNullableType()) return expression; + if (!expression.Type.IsValueType || expression.Type.IsNullableType()) return expression; - var operand = expression.NodeType == ExpressionType.Convert - ? ((UnaryExpression) expression).Operand - : expression; + var operand = expression.NodeType == ExpressionType.Convert + ? ((UnaryExpression) expression).Operand + : expression; - return Expression.Convert(operand, typeof(Nullable<>).MakeGenericType(expression.Type)); - } + return Expression.Convert(operand, typeof(Nullable<>).MakeGenericType(expression.Type)); + } - static Expression UnwrapConvertToNullable(Expression expression) + static Expression UnwrapConvertToNullable(Expression expression) { var unary = expression as UnaryExpression; if (unary != null && expression.NodeType == ExpressionType.Convert && expression.Type.IsNullableType()) @@ -233,11 +233,11 @@ static bool ExtractNullableArgument(Expression hasValue, Expression getValueOrDe MemberExpression memberExpression; if (IsHasValue(hasValue, out memberExpression)) { - expression = new GetValueOrDefaultRemover(memberExpression.Expression).Visit(getValueOrDefault); + expression = new GetValueOrDefaultRemover(memberExpression.Expression).Visit(getValueOrDefault); if (expression != getValueOrDefault) return true; } - + expression = null; return false; } @@ -252,12 +252,12 @@ static bool IsCoalesce(Expression hasValue, Expression getValueOrDefault, out Ex if (expression == callExpression.Object) return true; } - + expression = null; return false; } - static bool IsHasValue(Expression expression, out MemberExpression property) + static bool IsHasValue(Expression expression, out MemberExpression property) { property = expression as MemberExpression; return property != null && property.Member.Name == "HasValue" && property.Expression != null && property.Expression.Type.IsNullableType(); @@ -324,7 +324,7 @@ left is MethodCallExpression expression && protected override Expression VisitUnary(UnaryExpression node) { - if (node.NodeType == ExpressionType.Not && + if (node.NodeType == ExpressionType.Not && node.Operand is BinaryExpression binary && Invert(ref binary)) { @@ -350,40 +350,40 @@ static bool Invert(ref BinaryExpression expression) switch (expression.NodeType) { case ExpressionType.Equal: - { - expression = Expression.NotEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.NotEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.NotEqual: - { - expression = Expression.Equal(expression.Left, expression.Right); - return true; - } + { + expression = Expression.Equal(expression.Left, expression.Right); + return true; + } case ExpressionType.LessThan: - { - expression = Expression.GreaterThanOrEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.GreaterThanOrEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.LessThanOrEqual: - { - expression = Expression.GreaterThan(expression.Left, expression.Right); - return true; - } + { + expression = Expression.GreaterThan(expression.Left, expression.Right); + return true; + } case ExpressionType.GreaterThan: - { - expression = Expression.LessThanOrEqual(expression.Left, expression.Right); - return true; - } + { + expression = Expression.LessThanOrEqual(expression.Left, expression.Right); + return true; + } case ExpressionType.GreaterThanOrEqual: - { - expression = Expression.LessThan(expression.Left, expression.Right); - return true; - } + { + expression = Expression.LessThan(expression.Left, expression.Right); + return true; + } } return false; } - class GetValueOrDefaultRemover : ExpressionVisitor + class GetValueOrDefaultRemover :ExpressionVisitor { readonly Expression expected; @@ -417,19 +417,19 @@ protected override Expression VisitBinary(BinaryExpression node) return node.Update(left, conversion, right); } - protected override Expression VisitUnary(UnaryExpression node) - { - var before = node; - var operand = Visit(node.Operand); + protected override Expression VisitUnary(UnaryExpression node) + { + var before = node; + var operand = Visit(node.Operand); - if (operand != before.Operand) - { - operand = ConvertToNullable(operand); - } + if (operand != before.Operand) + { + operand = ConvertToNullable(operand); + } - return before.Update(operand); - } - } + return before.Update(operand); + } + } class GetValueOrDefaultToCoalesceConverter : ExpressionVisitor { @@ -446,7 +446,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return base.VisitMethodCall(node); } } - + class LinqExpressionUnwrapper : ExpressionVisitor { public static Expression Unwrap(Expression expression) @@ -459,7 +459,7 @@ public static Expression Unwrap(Expression expression) protected override Expression VisitMethodCall(MethodCallExpression node) { - if (node.Method.Name == nameof(Expression.Constant) && + if (node.Method.Name == nameof(Expression.Constant) && node.Method.DeclaringType == typeof(Expression) && node.Arguments[0] is ParameterExpression parameter) { From edf316cdd93d574ce0f00c409718e373c175c0c9 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 13 Oct 2022 14:14:26 +1300 Subject: [PATCH 3/6] Revert change from develop --- src/DelegateDecompiler/OptimizeExpressionVisitor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index 400927d..1f05ec0 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -461,7 +461,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == nameof(Expression.Constant) && node.Method.DeclaringType == typeof(Expression) && - node.Arguments[0] is ParameterExpression parameter) + node.Arguments[0] is Expression parameter) { return Expression.Constant(parameter); } From 24602078953aaa9cc9dff7c7b2b763f748496ad5 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 13 Oct 2022 15:43:07 +1300 Subject: [PATCH 4/6] Hopefully all scenarious are fixed --- .../DetailedListOfSupportedCommands.md | 8 ++- .../DetailedListOfSupportedCommandsWithSQL.md | 8 ++- .../SummaryOfSupportedCommands.md | 6 ++- ...Issue152.cs => Test01NestedExpressions.cs} | 12 ++--- .../DetailedListOfSupportedCommands.md | 6 ++- .../DetailedListOfSupportedCommandsWithSQL.md | 6 ++- .../SummaryOfSupportedCommands.md | 4 +- .../DetailedListOfSupportedCommands.md | 8 ++- .../DetailedListOfSupportedCommandsWithSQL.md | 14 +++++- .../SummaryOfSupportedCommands.md | 6 ++- .../DetailedListOfSupportedCommands.md | 8 ++- .../DetailedListOfSupportedCommandsWithSQL.md | 18 ++++++- .../SummaryOfSupportedCommands.md | 6 ++- .../OptimizeExpressionVisitor.cs | 49 ++++++++----------- 14 files changed, 112 insertions(+), 47 deletions(-) rename src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/{Test01Issue152.cs => Test01NestedExpressions.cs} (78%) diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 023f577..4691d13 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:20 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -143,5 +143,11 @@ More will appear as we move forward.* * DateTime Where Compare With Static Variable (line 35) +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- **Not Supported** + * Subquery As Context Extension Method (line 59) + + The End diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 39d5621..b520ee4 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:20 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -832,5 +832,11 @@ SELECT +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- **Not Supported** + * Subquery As Context Extension Method (line 59) + + The End diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 082d234..6d7d3a2 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:20 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -54,5 +54,9 @@ More will appear as we move forward.* * [Strings](../TestGroup50Types/Test01Strings.cs) (4 tests) * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) +### Group: Additional Features +- **Not Supported** + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) + The End diff --git a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs similarity index 78% rename from src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs rename to src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs index 292afdf..9dfa7b8 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01Issue152.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs @@ -1,7 +1,5 @@ using System.Linq; -using System.Net.Mail; using DelegateDecompiler.EntityFramework.Tests.EfItems; -using DelegateDecompiler.EntityFramework.Tests.EfItems.Abstracts; using DelegateDecompiler.EntityFramework.Tests.Helpers; using NUnit.Framework; @@ -10,13 +8,13 @@ namespace DelegateDecompiler.EntityFramework.Tests.TestGroup90AdditionalFeatures public static class EfTestDbContextExtensions { [Computed] - public static int GetFirstChildIdByParent(this EfTestDbContext context, int parentId) + public static int GetFirstChildIdByParent(this EfTestDbContext context, int pId) { - return context.EfChildren.Where(e => e.EfParentId == parentId).Select(e => e.EfChildId).FirstOrDefault(); + return context.EfChildren.Where(a => a.EfParentId == pId).Select(b => b.EfChildId).FirstOrDefault(); } } - class Test01Issue152 + class Test01NestedExpressions { private ClassEnvironment classEnv; @@ -33,7 +31,7 @@ class ParentIdWithFirstChildId public override bool Equals(object obj) { - return (obj as ParentIdWithFirstChildId)?.ParentId == ParentId && (obj as ParentIdWithFirstChildId)?.FirstChildId == FirstChildId; + return obj is ParentIdWithFirstChildId id && id.ParentId == ParentId && id.FirstChildId == FirstChildId; } public override int GetHashCode() @@ -54,7 +52,7 @@ public void TestSubqueryAsContextExtensionMethod() var linq = env.Db.EfParents.Select(x => new ParentIdWithFirstChildId() { ParentId = x.EfParentId, - FirstChildId = env.Db.EfChildren.Where(e => e.EfParentId == x.EfParentId).Select(e => e.EfChildId).FirstOrDefault() + FirstChildId = env.Db.EfChildren.Where(a => a.EfParentId == x.EfParentId).Select(b => b.EfChildId).FirstOrDefault() }).ToList(); //ATTEMPT diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 62d52a0..20c11b2 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -144,5 +144,9 @@ More will appear as we move forward.* * DateTime Where Compare With Static Variable (line 35) +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index a7fcfe7..50cc7c3 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -510,5 +510,9 @@ More will appear as we move forward.* +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index dcf240d..7f261b5 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -54,5 +54,7 @@ More will appear as we move forward.* * [Strings](../TestGroup50Types/Test01Strings.cs) (4 tests) * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) +### Group: Additional Features + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 3f1fc32..586791a 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -142,5 +142,11 @@ More will appear as we move forward.* * DateTime Where Compare With Static Variable (line 35) +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- Supported + * Subquery As Context Extension Method (line 68) + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index c26f45c..3d279d3 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -496,5 +496,17 @@ More will appear as we move forward.* +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- Supported + * Subquery As Context Extension Method (line 68) + * T-Sql executed is + +```SQL + +``` + + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 0fc390a..99e1f9c 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -54,5 +54,9 @@ More will appear as we move forward.* * [Strings](../TestGroup50Types/Test01Strings.cs) (4 tests) * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) +### Group: Additional Features +- Supported + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 3f1fc32..e68e05d 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -142,5 +142,11 @@ More will appear as we move forward.* * DateTime Where Compare With Static Variable (line 35) +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- Supported + * Subquery As Context Extension Method (line 68) + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 7ffb67b..3733f45 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -764,5 +764,21 @@ WHERE [e].[StartDate] > '2000-01-01T00:00:00.0000000' +### Group: Additional Features +#### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): +- Supported + * Subquery As Context Extension Method (line 68) + * T-Sql executed is + +```SQL +SELECT [e0].[EfParentId] AS [ParentId], COALESCE(( + SELECT TOP(1) [e].[EfChildId] + FROM [EfChildren] AS [e] + WHERE [e].[EfParentId] = [e0].[EfParentId]), 0) AS [FirstChildId] +FROM [EfParents] AS [e0] +``` + + + The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 0fc390a..70f32ec 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Tuesday, 14 December 2021 22:21 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -54,5 +54,9 @@ More will appear as we move forward.* * [Strings](../TestGroup50Types/Test01Strings.cs) (4 tests) * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) +### Group: Additional Features +- Supported + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) + The End diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index 1f05ec0..751bb5d 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -339,11 +339,16 @@ protected override Expression VisitMethodCall(MethodCallExpression node) if (node.Method.Name == nameof(Expression.Lambda) && node.Method.DeclaringType == typeof(Expression)) { - return LinqExpressionUnwrapper.Unwrap(node); + var call = base.VisitMethodCall(node); + return LinqExpressionUnwrapper.Unwrap(call); } return base.VisitMethodCall(node); } + static Expression EvaluateExpression(Expression node) + { + return Expression.Lambda>(node).Compile().Invoke(); + } static bool Invert(ref BinaryExpression expression) { @@ -452,51 +457,39 @@ class LinqExpressionUnwrapper : ExpressionVisitor public static Expression Unwrap(Expression expression) { var visit = new LinqExpressionUnwrapper().Visit(expression); - var func = Expression.Lambda>(visit).Compile(); - var output = UnwrappedParameterMerger.Merge(func()); - return Expression.Quote(output); + return Expression.Quote(EvaluateExpression(visit)); } protected override Expression VisitMethodCall(MethodCallExpression node) { - if (node.Method.Name == nameof(Expression.Constant) && - node.Method.DeclaringType == typeof(Expression) && - node.Arguments[0] is Expression parameter) + if (node.Method.Name == nameof(Expression.Constant) && + node.Method.DeclaringType == typeof(Expression)) { - return Expression.Constant(parameter); + var constant = ParametersDetector.ContainsParameters(node) + ? node.Arguments[0] + : EvaluateExpression(node); + return Expression.Constant(constant); } return base.VisitMethodCall(node); } } - class UnwrappedParameterMerger : ExpressionVisitor + class ParametersDetector : ExpressionVisitor { - private Dictionary parameters = new Dictionary(); - private LambdaExpression lambda; + bool hasParameters; - public static Expression Merge(Expression expression) + public static bool ContainsParameters(Expression node) { - var resolver = new UnwrappedParameterMerger(); - resolver.lambda = expression as LambdaExpression; - return resolver.Visit(resolver.lambda); + var detector = new ParametersDetector(); + detector.Visit(node); + return detector.hasParameters; } protected override Expression VisitParameter(ParameterExpression node) { - if (!parameters.TryGetValue(node.Name, out ParameterExpression parameter)) - { - for (var i = 0; i < lambda.Parameters.Count; i++) - { - if (node.Name == lambda.Parameters[i].Name) - { - node = lambda.Parameters[i]; - parameters.Add(node.Name, node); - break; - } - } - } - return node; + hasParameters = true; + return base.VisitParameter(node); } } From bc9e2cb53f1e1b3b71479373b05478090f5a3a7f Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 13 Oct 2022 15:52:34 +1300 Subject: [PATCH 5/6] Simplify logic --- src/DelegateDecompiler/OptimizeExpressionVisitor.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index 751bb5d..a4737c3 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -457,18 +457,17 @@ class LinqExpressionUnwrapper : ExpressionVisitor public static Expression Unwrap(Expression expression) { var visit = new LinqExpressionUnwrapper().Visit(expression); - return Expression.Quote(EvaluateExpression(visit)); + var func = Expression.Lambda>(visit).Compile(); + return Expression.Quote(func.Invoke()); } protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == nameof(Expression.Constant) && - node.Method.DeclaringType == typeof(Expression)) + node.Method.DeclaringType == typeof(Expression) && + ParametersDetector.ContainsParameters(node)) { - var constant = ParametersDetector.ContainsParameters(node) - ? node.Arguments[0] - : EvaluateExpression(node); - return Expression.Constant(constant); + return Expression.Constant(node.Arguments[0]); } return base.VisitMethodCall(node); From 3ce97c00abdb2b7f2d3c792efc6485f8bb9e1c29 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 13 Oct 2022 16:16:57 +1300 Subject: [PATCH 6/6] Deduplicate parameters --- .../DetailedListOfSupportedCommands.md | 6 ++-- .../DetailedListOfSupportedCommandsWithSQL.md | 30 +++++++++++++++++-- .../SummaryOfSupportedCommands.md | 4 +-- .../DetailedListOfSupportedCommands.md | 2 +- .../DetailedListOfSupportedCommandsWithSQL.md | 2 +- .../SummaryOfSupportedCommands.md | 2 +- .../DetailedListOfSupportedCommands.md | 2 +- .../DetailedListOfSupportedCommandsWithSQL.md | 2 +- .../SummaryOfSupportedCommands.md | 2 +- .../DetailedListOfSupportedCommands.md | 2 +- .../DetailedListOfSupportedCommandsWithSQL.md | 2 +- .../SummaryOfSupportedCommands.md | 2 +- .../OptimizeExpressionVisitor.cs | 28 +++++++++++++---- 13 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 4691d13..dfb6007 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -145,8 +145,8 @@ More will appear as we move forward.* ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): -- **Not Supported** - * Subquery As Context Extension Method (line 59) +- Supported + * Subquery As Context Extension Method (line 68) diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index b520ee4..2a6afcf 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -834,8 +834,32 @@ SELECT ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): -- **Not Supported** - * Subquery As Context Extension Method (line 59) +- Supported + * Subquery As Context Extension Method (line 68) + * T-Sql executed is + +```SQL +SELECT + [Project4].[EfParentId] AS [EfParentId], + CASE WHEN ([Project4].[C1] IS NULL) THEN 0 ELSE [Project4].[C2] END AS [C1] + FROM ( SELECT + [Project2].[EfParentId] AS [EfParentId], + [Project2].[C1] AS [C1], + (SELECT TOP (1) + [Extent3].[EfChildId] AS [EfChildId] + FROM [dbo].[EfChilds] AS [Extent3] + WHERE [Extent3].[EfParentId] = [Project2].[EfParentId]) AS [C2] + FROM ( SELECT + [Extent1].[EfParentId] AS [EfParentId], + (SELECT TOP (1) + [Extent2].[EfChildId] AS [EfChildId] + FROM [dbo].[EfChilds] AS [Extent2] + WHERE [Extent2].[EfParentId] = [Extent1].[EfParentId]) AS [C1] + FROM [dbo].[EfParents] AS [Extent1] + ) AS [Project2] + ) AS [Project4] +``` + diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 6d7d3a2..7980f43 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -55,7 +55,7 @@ More will appear as we move forward.* * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) ### Group: Additional Features -- **Not Supported** +- Supported * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 20c11b2..09b1c78 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 50cc7c3..178ff6a 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 7f261b5..b26867e 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:12 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 586791a..de7b009 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 3d279d3..49a81d7 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 99e1f9c..f36f68e 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:40 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index e68e05d..de7b009 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 3733f45..927842b 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 70f32ec..f36f68e 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore5.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 15:41 +## Documentation produced for DelegateDecompiler, version 0.30.0 on Thursday, 13 October 2022 16:11 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index a4737c3..05d1c8f 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -345,10 +345,6 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return base.VisitMethodCall(node); } - static Expression EvaluateExpression(Expression node) - { - return Expression.Lambda>(node).Compile().Invoke(); - } static bool Invert(ref BinaryExpression expression) { @@ -454,11 +450,13 @@ protected override Expression VisitMethodCall(MethodCallExpression node) class LinqExpressionUnwrapper : ExpressionVisitor { + readonly Dictionary replacements = new Dictionary(); + public static Expression Unwrap(Expression expression) { var visit = new LinqExpressionUnwrapper().Visit(expression); - var func = Expression.Lambda>(visit).Compile(); - return Expression.Quote(func.Invoke()); + var func = EvaluateExpression(visit); + return Expression.Quote(func); } protected override Expression VisitMethodCall(MethodCallExpression node) @@ -470,8 +468,26 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return Expression.Constant(node.Arguments[0]); } + if (node.Method.Name == nameof(Expression.Parameter) && + node.Method.DeclaringType == typeof(Expression)) + { + if (!replacements.TryGetValue(node, out var parameter)) + { + parameter = Expression.Constant(EvaluateExpression(node)); + replacements[node] = parameter; + } + + return parameter; + } + return base.VisitMethodCall(node); } + + static Expression EvaluateExpression(Expression visit) + { + var func = Expression.Lambda>(visit).Compile(); + return func.Invoke(); + } } class ParametersDetector : ExpressionVisitor