Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix New() support for Type + Fix GroupJoin() not working when using Linq-To-Entities (2) #208

Merged
merged 12 commits into from
Oct 19, 2018
8 changes: 7 additions & 1 deletion src-console/ConsoleAppEF2.0.2_InMemory/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.CustomTypeProviders;
Expand All @@ -25,6 +24,13 @@ public HashSet<Type> GetCustomTypes()

return set;
}

public Type ResolveType(string typeName)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();

return ResolveType(assemblies, typeName);
}
}

private static IQueryable GetQueryable()
Expand Down
7 changes: 7 additions & 0 deletions src-console/ConsoleAppEF2.0/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.CustomTypeProviders;
using ConsoleAppEF2.Database;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

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

return set;
}

public Type ResolveType(string typeName)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
return ResolveType(assemblies, typeName);
}
}

private static IQueryable GetQueryable()
Expand Down
8 changes: 8 additions & 0 deletions src-console/ConsoleAppEF2.1.1/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.CustomTypeProviders;
using ConsoleAppEF2.Database;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

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

return set;
}

public Type ResolveType(string typeName)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();

return ResolveType(assemblies, typeName);
}
}

private static IQueryable GetQueryable()
Expand Down
35 changes: 30 additions & 5 deletions src-console/ConsoleAppEF2.1.1_InMemory/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ namespace ConsoleAppEF2
{
static class Program
{
class C : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
public class NestedDto
{
public string Name { get; set; }

public class NestedDto2
{
public string Name2 { get; set; }
}
}

class NetCore21CustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
public HashSet<Type> GetCustomTypes()
{
Expand All @@ -26,6 +36,12 @@ public HashSet<Type> GetCustomTypes()

return set;
}

public Type ResolveType(string typeName)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
return ResolveType(assemblies, typeName);
}
}

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

static void Main(string[] args)
{
var config = new ParsingConfig
{
AllowNewToEvaluateAnyType = true,
CustomTypeProvider = new NetCore21CustomTypeProvider()
};

// Act
var testDataAsQueryable = new List<string>() { "name1", "name2" }.AsQueryable();
var projectedData = (IQueryable<NestedDto>)testDataAsQueryable.Select(config, $"new {typeof(NestedDto).FullName}(~ as Name)");
Console.WriteLine(projectedData.First().Name);
Console.WriteLine(projectedData.Last().Name);

IQueryable qry = GetQueryable();

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

var config = new ParsingConfig
{
CustomTypeProvider = new C()
};


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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>Dynamic Linq extensions for EntityFramework which adds Async support</Description>
<AssemblyTitle>EntityFramework.DynamicLinq</AssemblyTitle>
<VersionPrefix>1.0.8.18</VersionPrefix>
<VersionPrefix>1.0.9.1</VersionPrefix>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;net46</TargetFrameworks>
<DefineConstants>EF</DefineConstants>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support</Description>
<AssemblyTitle>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyTitle>
<VersionPrefix>1.0.8.18</VersionPrefix>
<VersionPrefix>1.0.9.1</VersionPrefix>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);EFCORE</DefineConstants>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
/// <summary>
/// The abstract <see cref="AbstractDynamicLinqCustomTypeProvider"/>. Find all types marked with <see cref="DynamicLinqTypeAttribute"/>.
/// The abstract DynamicLinqCustomTypeProvider which is used by the <see cref="IDynamicLinkCustomTypeProvider"/> and can be used by a custom TypeProvider like in .NET Core.
/// </summary>
public abstract class AbstractDynamicLinqCustomTypeProvider
{
Expand All @@ -30,6 +30,29 @@ protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull
#endif
}

/// <summary>
/// Resolve any type which is registered in the current application domain.
/// </summary>
/// <param name="assemblies">The assemblies to inspect.</param>
/// <param name="typeName">The typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
protected Type ResolveType([NotNull] IEnumerable<Assembly> assemblies, [NotNull] string typeName)
{
Check.NotNull(assemblies, nameof(assemblies));
Check.NotEmpty(typeName, nameof(typeName));

foreach (Assembly assembly in assemblies)
{
Type resolvedType = assembly.GetType(typeName, false, true);
if (resolvedType != null)
{
return resolvedType;
}
}

return null;
}

#if (WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD)
/// <summary>
/// Gets the assembly types in an Exception friendly way.
Expand All @@ -48,8 +71,10 @@ protected IEnumerable<TypeInfo> GetAssemblyTypes([NotNull] IEnumerable<Assembly>
{
definedTypes = assembly.DefinedTypes;
}
catch (Exception)
{ }
catch
{
// Ignore error
}

if (definedTypes != null)
{
Expand Down Expand Up @@ -78,8 +103,10 @@ protected IEnumerable<Type> GetAssemblyTypes([NotNull] IEnumerable<Assembly> ass
{
definedTypes = assembly.GetTypes();
}
catch (Exception)
{ }
catch
{
// Ignore error
}

if (definedTypes != null)
{
Expand All @@ -92,4 +119,4 @@ protected IEnumerable<Type> GetAssemblyTypes([NotNull] IEnumerable<Assembly> ass
}
#endif
}
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
#if !(WINDOWS_APP || UAP10_0)
using System.Collections.Generic;
using System.Linq.Dynamic.Core.Validation;
using System.Reflection;

namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
/// <summary>
/// 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.
/// 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.
///
/// Also provides functionality to resolve a Type in the current Application Domain.
///
/// This class is used as default for full .NET Framework, so not for .NET Core
/// </summary>
public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper();
private HashSet<Type> _customTypes;

/// <summary>
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand.
/// </summary>
/// <returns>
/// A <see cref="System.Collections.Generic.HashSet&lt;Type&gt;" /> list of custom types.
/// </returns>
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetCustomTypes"/>
public virtual HashSet<Type> GetCustomTypes()
{
if (_customTypes != null)
{
return _customTypes;
}
IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
return new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
}

/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveType"/>
public Type ResolveType(string typeName)
{
Check.NotEmpty(typeName, nameof(typeName));

IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
return _customTypes;
return ResolveType(assemblies, typeName);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using JetBrains.Annotations;

namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
/// <summary>
/// Interface for providing functionality to find custom types for or resolve any type.
/// </summary>
public interface IDynamicLinkCustomTypeProvider
{
/// <summary>
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand.
/// </summary>
/// <returns>A <see cref="HashSet&lt;Type&gt;" /> list of custom types.</returns>
HashSet<Type> GetCustomTypes();

/// <summary>
/// Resolve any type which is registered in the current application domain.
/// </summary>
/// <param name="typeName">The typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
Type ResolveType([NotNull] string typeName);
}
}

This file was deleted.

2 changes: 1 addition & 1 deletion src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
10 changes: 10 additions & 0 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1525,14 +1525,17 @@ Type FindType(string name)
{
return result;
}

if (_it != null && _it.Type.Name == name)
{
return _it.Type;
}

if (_parent != null && _parent.Type.Name == name)
{
return _parent.Type;
}

if (_root != null && _root.Type.Name == name)
{
return _root.Type;
Expand All @@ -1541,15 +1544,22 @@ Type FindType(string name)
{
return _it.Type;
}

if (_parent != null && _parent.Type.Namespace + "." + _parent.Type.Name == name)
{
return _parent.Type;
}

if (_root != null && _root.Type.Namespace + "." + _root.Type.Name == name)
{
return _root.Type;
}

if (_parsingConfig.AllowNewToEvaluateAnyType && _parsingConfig.CustomTypeProvider != null)
{
return _parsingConfig.CustomTypeProvider.ResolveType(name);
}

return null;
}

Expand Down
5 changes: 5 additions & 0 deletions src/System.Linq.Dynamic.Core/ParsingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
/// </summary>
public bool EvaluateGroupByAtDatabase { get; set; }

/// <summary>
/// Allows the New() keyword to evaluate any available Type.
/// </summary>
public bool AllowNewToEvaluateAnyType { get; set; } = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>This is a .NETStandard/ .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality.</Description>
<AssemblyTitle>System.Linq.Dynamic.Core</AssemblyTitle>
<VersionPrefix>1.0.8.18</VersionPrefix>
<VersionPrefix>1.0.9.1</VersionPrefix>
<Authors>Microsoft;Scott Guthrie;King Wilder;Nathan Arnott;Stef Heyenrath</Authors>
<TargetFrameworks>net35;net40;net45;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public HashSet<Type> GetCustomTypes()
return new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
}

public Type ResolveType(string typeName)
{
var assemblies = GetAssemblyListAsync().Result;
return ResolveType(assemblies, typeName);
}

private static async Task<List<Assembly>> GetAssemblyListAsync()
{
List<Assembly> assemblies = new List<Assembly>();
Expand Down
Loading