diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 82a7ccf..0ae1403 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.32.1.0 on Tuesday, 25 October 2022 19:36 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:49 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -147,7 +147,10 @@ More will appear as we move forward.* ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): - Supported - * Subquery As Context Extension Method (line 68) + * Subquery As Context Extension Method (line 69) + * Filter With Subquery Reference (line 112) +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 0f61cb3..c9ef176 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.32.1.0 on Tuesday, 25 October 2022 19:36 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:49 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework v6.1](http://msdn.microsoft.com/en-us/data/aa937723) (EF). @@ -849,7 +849,7 @@ SELECT ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): - Supported - * Subquery As Context Extension Method (line 68) + * Subquery As Context Extension Method (line 69) * T-Sql executed is ```SQL @@ -874,6 +874,32 @@ SELECT ) AS [Project4] ``` + * Filter With Subquery Reference (line 112) + * T-Sql executed is + +```SQL +SELECT + CASE WHEN ( EXISTS (SELECT + 1 AS [C1] + FROM [dbo].[EfParents] AS [Extent1] + WHERE EXISTS (SELECT + 1 AS [C1] + FROM ( SELECT + [Extent2].[EfParentId] AS [EfParentId], + (SELECT + COUNT(1) AS [A1] + FROM [dbo].[EfChilds] AS [Extent3] + WHERE [Extent2].[EfParentId] = [Extent3].[EfParentId]) AS [C1] + FROM [dbo].[EfParents] AS [Extent2] + ) AS [Project1] + WHERE (0 = [Project1].[C1]) AND ([Project1].[EfParentId] = [Extent1].[EfParentId]) + ) + )) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1] + FROM ( SELECT 1 AS X ) AS [SingleRowTable1] +``` + +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFramework.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index 1a7a23c..609564e 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.32.1.0 on Tuesday, 25 October 2022 19:36 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:49 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,8 +55,8 @@ More will appear as we move forward.* * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) ### Group: Additional Features -- Supported - * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) +- **Partially Supported** + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (2 of 3 tests passed) The End diff --git a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs index 9dfa7b8..8a0dfdd 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup90AdditionalFeatures/Test01NestedExpressions.cs @@ -1,5 +1,7 @@ -using System.Linq; +using System; +using System.Linq; using DelegateDecompiler.EntityFramework.Tests.EfItems; +using DelegateDecompiler.EntityFramework.Tests.EfItems.Abstracts; using DelegateDecompiler.EntityFramework.Tests.Helpers; using NUnit.Framework; @@ -68,5 +70,73 @@ public void TestSubqueryAsContextExtensionMethod() env.CompareAndLogList(linq, dd); } } + + [Test] +#if EF_CORE && !EF_CORE3 && !EF_CORE5 + [Ignore("Not natively supported in EF_CORE < 3")] +#endif + public void TestFailingSubqueryAsVariableReference() + { + using (var env = new MethodEnvironment(classEnv)) + { + //ATTEMPT + env.AboutToUseDelegateDecompiler(); + var referencedQuery = env.Db.Set().Where(it => it.Species == "Canis lupus"); + var query = env.Db.Set().Where(it => it.Animals.Intersect(referencedQuery).Any()).Decompile(); + + //VERIFY +#if EF_CORE + Assert.Throws(() => query.ToList()); +#else + Assert.Throws(() => query.ToList()); +#endif + } + } + + [Test] +#if EF_CORE && !EF_CORE3 && !EF_CORE5 + [Ignore("Not natively supported in EF_CORE < 3")] +#endif + public void TestSubqueryAsVariableReference() + { + using (var env = new MethodEnvironment(classEnv)) + { + //SETUP + var linq = env.Db.Set().Where(it => it.Animals.Intersect(env.Db.Set().Where(a => a is Dog)).Any()) + .ToList(); + + //ATTEMPT + env.AboutToUseDelegateDecompiler(); + var referencedQuery = env.Db.Set().Where(it => it.Species == "Canis lupus").Decompile(); + var query = env.Db.Set().Where(it => it.Animals.Intersect(referencedQuery).Any()).Decompile(); + + + var list = query.ToList(); + + //VERIFY + env.CompareAndLogList(linq, list); + } + } + + [Test] +#if EF_CORE && !EF_CORE3 && !EF_CORE5 + [Ignore("Not natively supported in EF_CORE < 3")] +#endif + public void TestFilterWithSubqueryReference() + { + using (var env = new MethodEnvironment(classEnv)) + { + //SETUP + var linq = env.Db.EfParents.Any(x => env.Db.EfParents.Where(p => p.Children.Count() == 0).Contains(x)); + + //ATTEMPT + env.AboutToUseDelegateDecompiler(); + var referencedQuery = env.Db.EfParents.Where(p => p.CountChildren == 0).Decompile(); + var dd = env.Db.EfParents.Decompile().Any(x => referencedQuery.Contains(x)); + + //VERIFY + env.CompareAndLogSingleton(linq, dd); + } + } } } \ No newline at end of file diff --git a/src/DelegateDecompiler.EntityFramework/AsyncDecompiledQueryProvider.cs b/src/DelegateDecompiler.EntityFramework/AsyncDecompiledQueryProvider.cs index 177fb1d..ef68fda 100644 --- a/src/DelegateDecompiler.EntityFramework/AsyncDecompiledQueryProvider.cs +++ b/src/DelegateDecompiler.EntityFramework/AsyncDecompiledQueryProvider.cs @@ -43,7 +43,7 @@ public override IQueryable CreateQuery(Expression expression) public override IQueryable CreateQuery(Expression expression) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return new AsyncDecompiledQueryable(this, inner.CreateQuery(decompiled)); } @@ -54,7 +54,7 @@ public Task ExecuteAsync(Expression expression, CancellationToken cancel { throw new InvalidOperationException("The source IQueryProvider doesn't implement IDbAsyncQueryProvider."); } - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return asyncProvider.ExecuteAsync(decompiled, cancellationToken); } @@ -65,7 +65,7 @@ public Task ExecuteAsync(Expression expression, CancellationTo { throw new InvalidOperationException("The source IQueryProvider doesn't implement IDbAsyncQueryProvider."); } - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return asyncProvider.ExecuteAsync(decompiled, cancellationToken); } } diff --git a/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 457d5b6..20b9774 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:41 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 3b763af..6c2c195 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:41 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 34cf522..087e996 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:41 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/AsyncDecompiledQueryProvider.cs b/src/DelegateDecompiler.EntityFrameworkCore/AsyncDecompiledQueryProvider.cs index 37e4802..96b4e3c 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore/AsyncDecompiledQueryProvider.cs +++ b/src/DelegateDecompiler.EntityFrameworkCore/AsyncDecompiledQueryProvider.cs @@ -39,7 +39,7 @@ protected IAsyncQueryProvider AsyncQueryProvider // ReSharper disable once VirtualMemberNeverOverridden.Global public virtual TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return (TResult)MethodCache.ExecuteAsync(AsyncQueryProvider, decompiled, cancellationToken); } @@ -95,19 +95,19 @@ public AsyncDecompiledQueryProvider(IQueryProvider inner) public override IQueryable CreateQuery(Expression expression) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return new EntityQueryable(this, decompiled); } public virtual IAsyncEnumerable ExecuteAsync(Expression expression) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return (IAsyncEnumerable)MethodCache.ExecuteAsync(AsyncQueryProvider, decompiled); } public new virtual Task ExecuteAsync(Expression expression, CancellationToken cancellationToken) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return (Task)MethodCache.ExecuteAsync(AsyncQueryProvider, decompiled, cancellationToken); } } diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 359b701..b739a23 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -146,7 +146,10 @@ More will appear as we move forward.* ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): - Supported - * Subquery As Context Extension Method (line 68) + * Subquery As Context Extension Method (line 69) + * Filter With Subquery Reference (line 112) +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index 1e001df..034dbc2 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -506,13 +506,22 @@ More will appear as we move forward.* ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): - Supported - * Subquery As Context Extension Method (line 68) + * Subquery As Context Extension Method (line 69) * T-Sql executed is ```SQL ``` + * Filter With Subquery Reference (line 112) + * T-Sql executed is + +```SQL + +``` + +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore3.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index add4b1f..f8d3c4f 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.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -55,8 +55,8 @@ More will appear as we move forward.* * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) ### Group: Additional Features -- Supported - * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) +- **Partially Supported** + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (2 of 3 tests passed) The End diff --git a/src/DelegateDecompiler.EntityFrameworkCore5/AsyncDecompiledQueryProvider.cs b/src/DelegateDecompiler.EntityFrameworkCore5/AsyncDecompiledQueryProvider.cs index 4bdf7b2..9b51e39 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore5/AsyncDecompiledQueryProvider.cs +++ b/src/DelegateDecompiler.EntityFrameworkCore5/AsyncDecompiledQueryProvider.cs @@ -27,14 +27,14 @@ IAsyncQueryProvider AsyncQueryProvider public virtual TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return AsyncQueryProvider.ExecuteAsync(decompiled, cancellationToken); } [SuppressMessage("EntityFramework", "EF1001")] public override IQueryable CreateQuery(Expression expression) { - var decompiled = expression.Decompile(); + var decompiled = expression.Decompile().Optimize(); return new EntityQueryable(this, decompiled); } } diff --git a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md index 359b701..b739a23 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommands.md @@ -1,6 +1,6 @@ Detail of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -146,7 +146,10 @@ More will appear as we move forward.* ### Group: Additional Features #### [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs): - Supported - * Subquery As Context Extension Method (line 68) + * Subquery As Context Extension Method (line 69) + * Filter With Subquery Reference (line 112) +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md index d36f0da..524a61b 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md +++ b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/DetailedListOfSupportedCommandsWithSQL.md @@ -1,6 +1,6 @@ Detail With Sql of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -775,7 +775,7 @@ 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) + * Subquery As Context Extension Method (line 69) * T-Sql executed is ```SQL @@ -786,6 +786,27 @@ SELECT [e].[EfParentId] AS [ParentId], COALESCE(( FROM [EfParents] AS [e] ``` + * Filter With Subquery Reference (line 112) + * T-Sql executed is + +```SQL +SELECT CASE + WHEN EXISTS ( + SELECT 1 + FROM [EfParents] AS [e] + WHERE EXISTS ( + SELECT 1 + FROM [EfParents] AS [e0] + WHERE (( + SELECT COUNT(*) + FROM [EfChildren] AS [e1] + WHERE [e0].[EfParentId] = [e1].[EfParentId]) = 0) AND ([e0].[EfParentId] = [e].[EfParentId]))) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +``` + +- **Not Supported** + * Subquery As Variable Reference (line 82) diff --git a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md index add4b1f..f8d3c4f 100644 --- a/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md +++ b/src/DelegateDecompiler.EntityFrameworkCore6.Tests/GeneratedDocumentation/SummaryOfSupportedCommands.md @@ -1,6 +1,6 @@ Summary of supported commands ============ -## Documentation produced for DelegateDecompiler, version 0.32.1.0 on Tuesday, 25 October 2022 19:37 +## Documentation produced for DelegateDecompiler, version 0.33.0.0 on Wednesday, 26 October 2022 12:42 This file documents what linq commands **DelegateDecompiler** supports when working with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) (EF). @@ -55,8 +55,8 @@ More will appear as we move forward.* * [DateTime](../TestGroup50Types/Test05DateTime.cs) (1 tests) ### Group: Additional Features -- Supported - * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (1 tests) +- **Partially Supported** + * [Nested Expressions](../TestGroup90AdditionalFeatures/Test01NestedExpressions.cs) (2 of 3 tests passed) The End diff --git a/src/DelegateDecompiler.Tests/NestedExpressionsTests.cs b/src/DelegateDecompiler.Tests/NestedExpressionsTests.cs index d19e5dd..7a533fb 100644 --- a/src/DelegateDecompiler.Tests/NestedExpressionsTests.cs +++ b/src/DelegateDecompiler.Tests/NestedExpressionsTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using NUnit.Framework; namespace DelegateDecompiler.Tests @@ -14,6 +15,21 @@ public class NestedExpressionsTests : DecompilerTestsBase int M1() => 0; static int M2() => 0; + readonly IQueryable fQref1 = Enumerable.Empty().AsQueryable().Decompile(); + static IQueryable fQref2 = Enumerable.Empty().AsQueryable().Decompile(); + [Decompile] + IQueryable pQref1 => Enumerable.Empty().AsQueryable(); + [Decompile] + static IQueryable pQref2 => Enumerable.Empty().AsQueryable(); + [Decompile] + IQueryable MQref1() => Enumerable.Empty().AsQueryable(); + [Decompile] + static IQueryable MQref2() => Enumerable.Empty().AsQueryable(); + [Decompile] + IQueryable ParamedMQref1(int floor) => Enumerable.Empty().AsQueryable().Where(x => x >= floor); + [Decompile] + static IQueryable ParamedMQref2(int floor) => Enumerable.Empty().AsQueryable().Where(x => x >= floor); + [Test] public void TestNestedExpression() { @@ -178,5 +194,107 @@ public void TestFuncWithStaticMethodClosure() ints => ints.SingleOrDefault(i => i == M2()) ); } + + [Test, Ignore("Difference is expected")] + public void TestQueryableBoundAsVariable() + { + IQueryable query = Enumerable.Empty().AsQueryable().Where(i => i >= 0).Decompile(); + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => query + ); + } + + [Test, Ignore("Difference is expected")] + public void TestQueryableRefFromField() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => fQref1.Where(i => i >= 0) + ); + } + + [Test, Ignore("Difference is expected")] + public void TestQueryableRefFromStaticField() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => fQref2.Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromProperty() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => pQref1.Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromStaticProperty() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => pQref2.Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromMethod() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => MQref1().Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromStaticMethod() + { + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(i => i >= 0), + ints => MQref2().Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromMethodWithBoundParameters() + { + var floor = 10; + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(x => x >= floor).Where(i => i >= 0), + ints => ParamedMQref1(floor).Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromStaticMethoWithBoundParameters() + { + var floor = 10; + Test, IQueryable>>( + ints => Enumerable.Empty().AsQueryable().Where(x => x >= floor).Where(i => i >= 0), + ints => ParamedMQref1(floor).Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromMethodWithUnboundParameters() + { + Test, int, IQueryable>>( + (ints, floor) => Enumerable.Empty().AsQueryable().Where(x => x >= floor).Where(i => i >= 0), + (ints, floor) => ParamedMQref1(floor).Where(i => i >= 0) + ); + } + + [Test] + public void TestQueryableRefFromStaticMethoWithUnboundParameters() + { + Test, int, IQueryable>>( + (ints, floor) => Enumerable.Empty().AsQueryable().Where(x => x >= floor).Where(i => i >= 0), + (ints, floor) => ParamedMQref1(floor).Where(i => i >= 0) + ); + } } } diff --git a/src/DelegateDecompiler/DecompileExtensions.cs b/src/DelegateDecompiler/DecompileExtensions.cs index 6b688d3..4158855 100644 --- a/src/DelegateDecompiler/DecompileExtensions.cs +++ b/src/DelegateDecompiler/DecompileExtensions.cs @@ -24,7 +24,7 @@ public static LambdaExpression Decompile(this Delegate @delegate) { {expression.Parameters[0], Expression.Constant(@delegate.Target)} }); - var transformed = visitor.Visit(expression.Body); + var transformed = visitor.Visit(expression.Body).Optimize(); return Expression.Lambda(transformed, expression.Parameters.Skip(1)); } @@ -35,7 +35,9 @@ public static LambdaExpression Decompile(this MethodInfo method) public static LambdaExpression Decompile(this MethodInfo method, Type declaringType) { - return Cache.GetOrAdd(Tuple.Create(declaringType, method), DecompileDelegate).Value; + return (LambdaExpression)Cache + .GetOrAdd(Tuple.Create(declaringType, method), DecompileDelegate) + .Value.Decompile(); } public static IQueryable Decompile(this IQueryable self) diff --git a/src/DelegateDecompiler/DecompiledQueryable.cs b/src/DelegateDecompiler/DecompiledQueryable.cs index 6fb33bd..9a22ba0 100644 --- a/src/DelegateDecompiler/DecompiledQueryable.cs +++ b/src/DelegateDecompiler/DecompiledQueryable.cs @@ -6,7 +6,7 @@ namespace DelegateDecompiler { - public class DecompiledQueryable : IOrderedQueryable + public class DecompiledQueryable : IDecompiledQueryable, IOrderedQueryable { private readonly IQueryable inner; private readonly IQueryProvider provider; diff --git a/src/DelegateDecompiler/IDecompiledQueryable.cs b/src/DelegateDecompiler/IDecompiledQueryable.cs new file mode 100644 index 0000000..b896737 --- /dev/null +++ b/src/DelegateDecompiler/IDecompiledQueryable.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DelegateDecompiler +{ + public interface IDecompiledQueryable + { + } +} diff --git a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs index f397f4f..8f30195 100644 --- a/src/DelegateDecompiler/OptimizeExpressionVisitor.cs +++ b/src/DelegateDecompiler/OptimizeExpressionVisitor.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace DelegateDecompiler { @@ -339,6 +341,20 @@ node.Operand is BinaryExpression binary && return base.VisitUnary(node); } + protected override Expression VisitMember(MemberExpression node) + { + if (typeof(IQueryable).IsAssignableFrom(node.Type)) + { + if (!(node.Expression is ParameterExpression) && node.Member is FieldInfo) + { + var referencedQueryable = node.Evaluate(); + if (referencedQueryable is IDecompiledQueryable) + return Visit(referencedQueryable.Expression); + } + } + return base.VisitMember(node); + } + protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == nameof(Expression.Lambda) && @@ -347,7 +363,13 @@ protected override Expression VisitMethodCall(MethodCallExpression node) var call = base.VisitMethodCall(node); return LinqExpressionUnwrapper.Unwrap(call); } - + if (typeof(IQueryable).IsAssignableFrom(node.Type)) + { + if (Configuration.Instance.ShouldDecompile(node.Method)) + { + return Visit(node.Decompile()); + } + } return base.VisitMethodCall(node); }