Skip to content

Commit b85093e

Browse files
authored
Fix New() support for Type + Fix GroupJoin() not working when using Linq-To-Entities (2) (#208)
* Fix Parsing Config not passed down to expression parser in JOIN * Use IDynamicLinkCustomTypeProvider to Resolve a Type * Small update on tests
1 parent 0967e9a commit b85093e

File tree

21 files changed

+278
-57
lines changed

21 files changed

+278
-57
lines changed

src-console/ConsoleAppEF2.0.2_InMemory/Program.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Dynamic;
43
using System.Linq;
54
using System.Linq.Dynamic.Core;
65
using System.Linq.Dynamic.Core.CustomTypeProviders;
@@ -25,6 +24,13 @@ public HashSet<Type> GetCustomTypes()
2524

2625
return set;
2726
}
27+
28+
public Type ResolveType(string typeName)
29+
{
30+
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
31+
32+
return ResolveType(assemblies, typeName);
33+
}
2834
}
2935

3036
private static IQueryable GetQueryable()

src-console/ConsoleAppEF2.0/Program.cs

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq.Dynamic.Core;
55
using System.Linq.Dynamic.Core.CustomTypeProviders;
66
using ConsoleAppEF2.Database;
7+
using JetBrains.Annotations;
78
using Microsoft.EntityFrameworkCore;
89
using Newtonsoft.Json;
910

@@ -23,6 +24,12 @@ public HashSet<Type> GetCustomTypes()
2324

2425
return set;
2526
}
27+
28+
public Type ResolveType(string typeName)
29+
{
30+
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
31+
return ResolveType(assemblies, typeName);
32+
}
2633
}
2734

2835
private static IQueryable GetQueryable()

src-console/ConsoleAppEF2.1.1/Program.cs

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq.Dynamic.Core;
55
using System.Linq.Dynamic.Core.CustomTypeProviders;
66
using ConsoleAppEF2.Database;
7+
using JetBrains.Annotations;
78
using Microsoft.EntityFrameworkCore;
89
using Newtonsoft.Json;
910

@@ -23,6 +24,13 @@ public HashSet<Type> GetCustomTypes()
2324

2425
return set;
2526
}
27+
28+
public Type ResolveType(string typeName)
29+
{
30+
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
31+
32+
return ResolveType(assemblies, typeName);
33+
}
2634
}
2735

2836
private static IQueryable GetQueryable()

src-console/ConsoleAppEF2.1.1_InMemory/Program.cs

+30-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,17 @@ namespace ConsoleAppEF2
1313
{
1414
static class Program
1515
{
16-
class C : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
16+
public class NestedDto
17+
{
18+
public string Name { get; set; }
19+
20+
public class NestedDto2
21+
{
22+
public string Name2 { get; set; }
23+
}
24+
}
25+
26+
class NetCore21CustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
1727
{
1828
public HashSet<Type> GetCustomTypes()
1929
{
@@ -26,6 +36,12 @@ public HashSet<Type> GetCustomTypes()
2636

2737
return set;
2838
}
39+
40+
public Type ResolveType(string typeName)
41+
{
42+
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
43+
return ResolveType(assemblies, typeName);
44+
}
2945
}
3046

3147
private static object GetObj()
@@ -150,6 +166,18 @@ private static TResult Execute<TResult>(MethodInfo operatorMethodInfo, IQueryabl
150166

151167
static void Main(string[] args)
152168
{
169+
var config = new ParsingConfig
170+
{
171+
AllowNewToEvaluateAnyType = true,
172+
CustomTypeProvider = new NetCore21CustomTypeProvider()
173+
};
174+
175+
// Act
176+
var testDataAsQueryable = new List<string>() { "name1", "name2" }.AsQueryable();
177+
var projectedData = (IQueryable<NestedDto>)testDataAsQueryable.Select(config, $"new {typeof(NestedDto).FullName}(~ as Name)");
178+
Console.WriteLine(projectedData.First().Name);
179+
Console.WriteLine(projectedData.Last().Name);
180+
153181
IQueryable qry = GetQueryable();
154182

155183
var result = qry.Select("it").OrderBy("Value");
@@ -183,10 +211,7 @@ static void Main(string[] args)
183211
var any2 = anyTest.Where("values.Contains(1)");
184212
Console.WriteLine("any2 {0}", JsonConvert.SerializeObject(any2, Formatting.Indented));
185213

186-
var config = new ParsingConfig
187-
{
188-
CustomTypeProvider = new C()
189-
};
214+
190215

191216
var dateLastModified = new DateTime(2018, 1, 15);
192217

src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>Dynamic Linq extensions for EntityFramework which adds Async support</Description>
44
<AssemblyTitle>EntityFramework.DynamicLinq</AssemblyTitle>
5-
<VersionPrefix>1.0.8.18</VersionPrefix>
5+
<VersionPrefix>1.0.9.1</VersionPrefix>
66
<Authors>Stef Heyenrath</Authors>
77
<TargetFrameworks>net45;net46</TargetFrameworks>
88
<DefineConstants>EF</DefineConstants>

src/Microsoft.EntityFrameworkCore.DynamicLinq/Microsoft.EntityFrameworkCore.DynamicLinq.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support</Description>
44
<AssemblyTitle>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyTitle>
5-
<VersionPrefix>1.0.8.18</VersionPrefix>
5+
<VersionPrefix>1.0.9.1</VersionPrefix>
66
<Authors>Stef Heyenrath</Authors>
77
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
88
<DefineConstants>$(DefineConstants);EFCORE</DefineConstants>

src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs

+33-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace System.Linq.Dynamic.Core.CustomTypeProviders
77
{
88
/// <summary>
9-
/// The abstract <see cref="AbstractDynamicLinqCustomTypeProvider"/>. Find all types marked with <see cref="DynamicLinqTypeAttribute"/>.
9+
/// The abstract DynamicLinqCustomTypeProvider which is used by the <see cref="IDynamicLinkCustomTypeProvider"/> and can be used by a custom TypeProvider like in .NET Core.
1010
/// </summary>
1111
public abstract class AbstractDynamicLinqCustomTypeProvider
1212
{
@@ -30,6 +30,29 @@ protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull
3030
#endif
3131
}
3232

33+
/// <summary>
34+
/// Resolve any type which is registered in the current application domain.
35+
/// </summary>
36+
/// <param name="assemblies">The assemblies to inspect.</param>
37+
/// <param name="typeName">The typename to resolve.</param>
38+
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
39+
protected Type ResolveType([NotNull] IEnumerable<Assembly> assemblies, [NotNull] string typeName)
40+
{
41+
Check.NotNull(assemblies, nameof(assemblies));
42+
Check.NotEmpty(typeName, nameof(typeName));
43+
44+
foreach (Assembly assembly in assemblies)
45+
{
46+
Type resolvedType = assembly.GetType(typeName, false, true);
47+
if (resolvedType != null)
48+
{
49+
return resolvedType;
50+
}
51+
}
52+
53+
return null;
54+
}
55+
3356
#if (WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD)
3457
/// <summary>
3558
/// Gets the assembly types in an Exception friendly way.
@@ -48,8 +71,10 @@ protected IEnumerable<TypeInfo> GetAssemblyTypes([NotNull] IEnumerable<Assembly>
4871
{
4972
definedTypes = assembly.DefinedTypes;
5073
}
51-
catch (Exception)
52-
{ }
74+
catch
75+
{
76+
// Ignore error
77+
}
5378

5479
if (definedTypes != null)
5580
{
@@ -78,8 +103,10 @@ protected IEnumerable<Type> GetAssemblyTypes([NotNull] IEnumerable<Assembly> ass
78103
{
79104
definedTypes = assembly.GetTypes();
80105
}
81-
catch (Exception)
82-
{ }
106+
catch
107+
{
108+
// Ignore error
109+
}
83110

84111
if (definedTypes != null)
85112
{
@@ -92,4 +119,4 @@ protected IEnumerable<Type> GetAssemblyTypes([NotNull] IEnumerable<Assembly> ass
92119
}
93120
#endif
94121
}
95-
}
122+
}

src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs

+17-14
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
11
#if !(WINDOWS_APP || UAP10_0)
22
using System.Collections.Generic;
3+
using System.Linq.Dynamic.Core.Validation;
34
using System.Reflection;
45

56
namespace System.Linq.Dynamic.Core.CustomTypeProviders
67
{
78
/// <summary>
8-
/// The default <see cref="IDynamicLinkCustomTypeProvider"/>. Scans the current AppDomain for all types marked with <see cref="DynamicLinqTypeAttribute"/>, and adds them as custom Dynamic Link types.
9+
/// The default <see cref="IDynamicLinkCustomTypeProvider"/>.
10+
/// Scans the current AppDomain for all types marked with <see cref="DynamicLinqTypeAttribute"/>, and adds them as custom Dynamic Link types.
11+
///
12+
/// Also provides functionality to resolve a Type in the current Application Domain.
13+
///
14+
/// This class is used as default for full .NET Framework, so not for .NET Core
915
/// </summary>
1016
public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
1117
{
1218
private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper();
13-
private HashSet<Type> _customTypes;
1419

15-
/// <summary>
16-
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand.
17-
/// </summary>
18-
/// <returns>
19-
/// A <see cref="System.Collections.Generic.HashSet&lt;Type&gt;" /> list of custom types.
20-
/// </returns>
20+
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetCustomTypes"/>
2121
public virtual HashSet<Type> GetCustomTypes()
2222
{
23-
if (_customTypes != null)
24-
{
25-
return _customTypes;
26-
}
23+
IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
24+
return new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
25+
}
26+
27+
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveType"/>
28+
public Type ResolveType(string typeName)
29+
{
30+
Check.NotEmpty(typeName, nameof(typeName));
2731

2832
IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
29-
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
30-
return _customTypes;
33+
return ResolveType(assemblies, typeName);
3134
}
3235
}
3336
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Collections.Generic;
2+
using JetBrains.Annotations;
3+
4+
namespace System.Linq.Dynamic.Core.CustomTypeProviders
5+
{
6+
/// <summary>
7+
/// Interface for providing functionality to find custom types for or resolve any type.
8+
/// </summary>
9+
public interface IDynamicLinkCustomTypeProvider
10+
{
11+
/// <summary>
12+
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand.
13+
/// </summary>
14+
/// <returns>A <see cref="HashSet&lt;Type&gt;" /> list of custom types.</returns>
15+
HashSet<Type> GetCustomTypes();
16+
17+
/// <summary>
18+
/// Resolve any type which is registered in the current application domain.
19+
/// </summary>
20+
/// <param name="typeName">The typename to resolve.</param>
21+
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
22+
Type ResolveType([NotNull] string typeName);
23+
}
24+
}

src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinkTypeProvider.cs

-16
This file was deleted.

src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [CanBeNull]
697697
typeof(Queryable), nameof(Queryable.GroupJoin),
698698
new[] { outer.ElementType, innerType, outerSelectorLambda.Body.Type, resultSelectorLambda.Body.Type },
699699
outer.Expression,
700-
Expression.Constant(inner),
700+
inner.AsQueryable().Expression,
701701
Expression.Quote(outerSelectorLambda),
702702
Expression.Quote(innerSelectorLambda),
703703
Expression.Quote(resultSelectorLambda)));

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+10
Original file line numberDiff line numberDiff line change
@@ -1525,14 +1525,17 @@ Type FindType(string name)
15251525
{
15261526
return result;
15271527
}
1528+
15281529
if (_it != null && _it.Type.Name == name)
15291530
{
15301531
return _it.Type;
15311532
}
1533+
15321534
if (_parent != null && _parent.Type.Name == name)
15331535
{
15341536
return _parent.Type;
15351537
}
1538+
15361539
if (_root != null && _root.Type.Name == name)
15371540
{
15381541
return _root.Type;
@@ -1541,15 +1544,22 @@ Type FindType(string name)
15411544
{
15421545
return _it.Type;
15431546
}
1547+
15441548
if (_parent != null && _parent.Type.Namespace + "." + _parent.Type.Name == name)
15451549
{
15461550
return _parent.Type;
15471551
}
1552+
15481553
if (_root != null && _root.Type.Namespace + "." + _root.Type.Name == name)
15491554
{
15501555
return _root.Type;
15511556
}
15521557

1558+
if (_parsingConfig.AllowNewToEvaluateAnyType && _parsingConfig.CustomTypeProvider != null)
1559+
{
1560+
return _parsingConfig.CustomTypeProvider.ResolveType(name);
1561+
}
1562+
15531563
return null;
15541564
}
15551565

src/System.Linq.Dynamic.Core/ParsingConfig.cs

+5
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,10 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider
6262
/// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation
6363
/// </summary>
6464
public bool EvaluateGroupByAtDatabase { get; set; }
65+
66+
/// <summary>
67+
/// Allows the New() keyword to evaluate any available Type.
68+
/// </summary>
69+
public bool AllowNewToEvaluateAnyType { get; set; } = false;
6570
}
6671
}

src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>This is a .NETStandard/ .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality.</Description>
44
<AssemblyTitle>System.Linq.Dynamic.Core</AssemblyTitle>
5-
<VersionPrefix>1.0.8.18</VersionPrefix>
5+
<VersionPrefix>1.0.9.1</VersionPrefix>
66
<Authors>Microsoft;Scott Guthrie;King Wilder;Nathan Arnott;Stef Heyenrath</Authors>
77
<TargetFrameworks>net35;net40;net45;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
88
<GenerateDocumentationFile>true</GenerateDocumentationFile>

test-uap/WindowsUniversalTestApp14393/WindowsAppCustomTypeProvider.cs

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public HashSet<Type> GetCustomTypes()
1717
return new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
1818
}
1919

20+
public Type ResolveType(string typeName)
21+
{
22+
var assemblies = GetAssemblyListAsync().Result;
23+
return ResolveType(assemblies, typeName);
24+
}
25+
2026
private static async Task<List<Assembly>> GetAssemblyListAsync()
2127
{
2228
List<Assembly> assemblies = new List<Assembly>();

0 commit comments

Comments
 (0)