From 56668c6907006939bbf68eb52fc6e6e20a954a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa?= Date: Tue, 4 Sep 2018 09:08:03 +0200 Subject: [PATCH 1/6] Fix Parsing Config not passed down to expression parser in JOIN --- .../DynamicQueryableExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index e3a82f54..0a32c0da 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -683,7 +683,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [CanBeNull] LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); - CheckOuterAndInnerTypes(createParameterCtor, outerType, innerType, outerKeySelector, innerKeySelector, ref outerSelectorLambda, ref innerSelectorLambda, args); + CheckOuterAndInnerTypes(config, createParameterCtor, outerType, innerType, outerKeySelector, innerKeySelector, ref outerSelectorLambda, ref innerSelectorLambda, args); ParameterExpression[] parameters = { @@ -739,7 +739,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [CanBeNull] Parsi LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); - CheckOuterAndInnerTypes(createParameterCtor, outerType, innerType, outerKeySelector, innerKeySelector, ref outerSelectorLambda, ref innerSelectorLambda, args); + CheckOuterAndInnerTypes(config, createParameterCtor, outerType, innerType, outerKeySelector, innerKeySelector, ref outerSelectorLambda, ref innerSelectorLambda, args); ParameterExpression[] parameters = { @@ -1923,7 +1923,7 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] Lambd #endregion #region Private Helpers - private static void CheckOuterAndInnerTypes(bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object[] args) + private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object[] args) { Type outerSelectorReturnType = outerSelectorLambda.Body.Type; Type innerSelectorReturnType = innerSelectorLambda.Body.Type; @@ -1941,12 +1941,12 @@ private static void CheckOuterAndInnerTypes(bool createParameterCtor, Type outer if (TypeHelper.IsNullableType(outerSelectorReturnType) && !TypeHelper.IsNullableType(innerSelectorReturnType)) { innerSelectorReturnType = ExpressionParser.ToNullableType(innerSelectorReturnType); - innerSelectorLambda = DynamicExpressionParser.ParseLambda(createParameterCtor, innerType, innerSelectorReturnType, innerKeySelector, args); + innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, innerSelectorReturnType, innerKeySelector, args); } else if (!TypeHelper.IsNullableType(outerSelectorReturnType) && TypeHelper.IsNullableType(innerSelectorReturnType)) { outerSelectorReturnType = ExpressionParser.ToNullableType(outerSelectorReturnType); - outerSelectorLambda = DynamicExpressionParser.ParseLambda(createParameterCtor, outerType, outerSelectorReturnType, outerKeySelector, args); + outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, outerSelectorReturnType, outerKeySelector, args); } // If types are still not the same, throw an Exception From cea22d3d94f156bf0689f35ae1bf863fd9515965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa?= Date: Tue, 16 Oct 2018 10:34:10 +0200 Subject: [PATCH 2/6] XX --- .../Parser/ExpressionParser.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 95f981bc..3764fb4b 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1542,6 +1542,18 @@ Type FindType(string name) { return _root.Type; } + if (_it != null && _it.Type.FullName == name) + { + return _it.Type; + } + if (_parent != null && _parent.Type.FullName == name) + { + return _parent.Type; + } + if (_root != null && _root.Type.FullName == name) + { + return _root.Type; + } return null; } From 12f8f3885bfd54d4fdc6a79b319871a67b90c93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa?= Date: Tue, 16 Oct 2018 10:38:52 +0200 Subject: [PATCH 3/6] XX --- src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index 0a32c0da..7a487fe8 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -697,7 +697,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [CanBeNull] typeof(Queryable), nameof(Queryable.GroupJoin), new[] { outer.ElementType, innerType, outerSelectorLambda.Body.Type, resultSelectorLambda.Body.Type }, outer.Expression, - Expression.Constant(inner), + inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultSelectorLambda))); From e21a949885747084ed11d4d1209f1ada23dbeda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa?= Date: Tue, 16 Oct 2018 11:52:58 +0200 Subject: [PATCH 4/6] XX --- .../Parser/ExpressionParser.cs | 12 +----- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 5 +++ .../QueryableTests.Select.cs | 37 +++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index ffb2ea49..2b22e203 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1549,17 +1549,9 @@ Type FindType(string name) { return _root.Type; } - if (_it != null && _it.Type.FullName == name) + if (this._parsingConfig.AllowNewToEvaluateAnyType && Type.GetType(name) != null) { - return _it.Type; - } - if (_parent != null && _parent.Type.FullName == name) - { - return _parent.Type; - } - if (_root != null && _root.Type.FullName == name) - { - return _root.Type; + return Type.GetType(name); } return null; diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index cc0414a5..d4adfa7d 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -62,5 +62,10 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider /// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation /// public bool EvaluateGroupByAtDatabase { get; set; } + + /// + /// Allows the New() keyword to evaluate any available Type + /// + public bool AllowNewToEvaluateAnyType { get; set; } = false; } } diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index 41210139..7aa49386 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Data.Entity.Infrastructure; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers.Models; using Linq.PropertyTranslator.Core; @@ -169,6 +170,16 @@ public class Example public DayOfWeek DOW { get; set; } public int Sec { get; set; } public int? SecNull { get; set; } + + public class NestedDto + { + public string Name { get; set; } + + public class NestedDto2 + { + public string Name2 { get; set; } + } + } } public class ExampleWithConstructor @@ -227,6 +238,32 @@ public void Select_Dynamic_IntoTypeWithNullableProperties2() Check.That(resultDynamic.Last()).Equals(result.Last()); } + [Fact] + public void Select_Dynamic_IntoKnownNestedType() + { + // Act + IQueryable data = new List() { "name1", "name2" }.AsQueryable(); + IQueryable projectedData = + (IQueryable) data.Select($"new {typeof(Example.NestedDto).FullName}(~ as Name)"); + + // Assert + Check.That(projectedData.First().Name).Equals("name1"); + Check.That(projectedData.Last().Name).Equals("name2"); + } + + [Fact] + public void Select_Dynamic_IntoKnownNestedTypeSecondLevel() + { + // Act + IQueryable data = new List() { "name1", "name2" }.AsQueryable(); + IQueryable projectedData = + (IQueryable)data.Select($"new {typeof(Example.NestedDto.NestedDto2).FullName}(~ as Name)"); + + // Assert + Check.That(projectedData.First().Name).Equals("name1"); + Check.That(projectedData.Last().Name).Equals("name2"); + } + [Fact] public void Select_Dynamic_Exceptions() { From 89794d5d0f1b8ee5fa8c21673d0d00c8d42db186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa?= Date: Tue, 16 Oct 2018 12:38:27 +0200 Subject: [PATCH 5/6] fixes --- .../QueryableTests.Select.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index 7aa49386..bd0632b7 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.Data.Entity.Infrastructure; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers.Models; using Linq.PropertyTranslator.Core; @@ -241,10 +240,13 @@ public void Select_Dynamic_IntoTypeWithNullableProperties2() [Fact] public void Select_Dynamic_IntoKnownNestedType() { + var config = new ParsingConfig(); + config.AllowNewToEvaluateAnyType = true; + // Act IQueryable data = new List() { "name1", "name2" }.AsQueryable(); IQueryable projectedData = - (IQueryable) data.Select($"new {typeof(Example.NestedDto).FullName}(~ as Name)"); + (IQueryable) data.Select(config, $"new {typeof(Example.NestedDto).FullName}(~ as Name)"); // Assert Check.That(projectedData.First().Name).Equals("name1"); @@ -254,10 +256,13 @@ public void Select_Dynamic_IntoKnownNestedType() [Fact] public void Select_Dynamic_IntoKnownNestedTypeSecondLevel() { + var config = new ParsingConfig(); + config.AllowNewToEvaluateAnyType = true; + // Act IQueryable data = new List() { "name1", "name2" }.AsQueryable(); IQueryable projectedData = - (IQueryable)data.Select($"new {typeof(Example.NestedDto.NestedDto2).FullName}(~ as Name)"); + (IQueryable)data.Select(config, $"new {typeof(Example.NestedDto.NestedDto2).FullName}(~ as Name)"); // Assert Check.That(projectedData.First().Name).Equals("name1"); From ddfd3294088958959e0c29134c16c83057eccc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa=20Garc=C3=ADa?= Date: Wed, 17 Oct 2018 10:37:42 +0200 Subject: [PATCH 6/6] Fixes --- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 46 +++++++++++++++++++ .../QueryableTests.Select.cs | 15 ++++-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index d4adfa7d..59bae863 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -1,4 +1,5 @@ using System.Linq.Dynamic.Core.CustomTypeProviders; +using System.Reflection; namespace System.Linq.Dynamic.Core { @@ -7,6 +8,26 @@ namespace System.Linq.Dynamic.Core /// public class ParsingConfig { + /// + /// Get an instance of ParsingConfig + /// + public ParsingConfig() + { +#if !(DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD) + AppDomain.CurrentDomain.TypeResolve += this.CurrentDomain_TypeResolve; +#endif + } + + /// + /// Cleanup + /// + ~ParsingConfig() + { +#if !(DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD) + AppDomain.CurrentDomain.TypeResolve -= this.CurrentDomain_TypeResolve; +#endif + } + /// /// Default ParsingConfig /// @@ -67,5 +88,30 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider /// Allows the New() keyword to evaluate any available Type /// public bool AllowNewToEvaluateAnyType { get; set; } = false; + +#if !(DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD) + /// + /// Custom type resolver to allow ExpressionParser to find any type + /// registered in the current application domain. You can add additional + /// type resolvers in your application. + /// + /// + /// + /// + protected Assembly CurrentDomain_TypeResolve(object sender, ResolveEventArgs args) + { + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + Type t = assembly.GetType(args.Name, false, true); + + if (t != null) + { + return assembly; + } + } + + return null; + } +#endif } } diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index bd0632b7..32163f8a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -240,6 +240,10 @@ public void Select_Dynamic_IntoTypeWithNullableProperties2() [Fact] public void Select_Dynamic_IntoKnownNestedType() { + +#if (DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD) + return; +#endif var config = new ParsingConfig(); config.AllowNewToEvaluateAnyType = true; @@ -256,17 +260,22 @@ public void Select_Dynamic_IntoKnownNestedType() [Fact] public void Select_Dynamic_IntoKnownNestedTypeSecondLevel() { + +#if (DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD) + return; +#endif + var config = new ParsingConfig(); config.AllowNewToEvaluateAnyType = true; // Act IQueryable data = new List() { "name1", "name2" }.AsQueryable(); IQueryable projectedData = - (IQueryable)data.Select(config, $"new {typeof(Example.NestedDto.NestedDto2).FullName}(~ as Name)"); + (IQueryable)data.Select(config, $"new {typeof(Example.NestedDto.NestedDto2).FullName}(~ as Name2)"); // Assert - Check.That(projectedData.First().Name).Equals("name1"); - Check.That(projectedData.Last().Name).Equals("name2"); + Check.That(projectedData.First().Name2).Equals("name1"); + Check.That(projectedData.Last().Name2).Equals("name2"); } [Fact]