diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln index 896175b6..763c7fef 100644 --- a/System.Linq.Dynamic.Core.sln +++ b/System.Linq.Dynamic.Core.sln @@ -151,6 +151,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeFirst.ConsoleApp", "src EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeFirst.ConsoleApp8", "src-examples\CodeFirst.ConsoleApp8\CodeFirst.ConsoleApp8.csproj", "{68C7FF71-54F6-4D68-B419-65D1B10206D4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Host", "src-console\Demo.Host\Demo.Host.csproj", "{D8368319-F370-4071-9411-A3DADB234330}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Plugin", "src-console\Demo.Plugin\Demo.Plugin.csproj", "{B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -869,6 +873,22 @@ Global {51074A4C-15C2-4E72-81F2-2FC53903553B}.Release|x64.Build.0 = Release|Any CPU {51074A4C-15C2-4E72-81F2-2FC53903553B}.Release|x86.ActiveCfg = Release|Any CPU {51074A4C-15C2-4E72-81F2-2FC53903553B}.Release|x86.Build.0 = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|ARM.Build.0 = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x64.Build.0 = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x86.Build.0 = Debug|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|Any CPU.Build.0 = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|ARM.ActiveCfg = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|ARM.Build.0 = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x64.ActiveCfg = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x64.Build.0 = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x86.ActiveCfg = Release|Any CPU + {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x86.Build.0 = Release|Any CPU {E36D1A08-F3ED-48C7-9DBF-8F625974A6C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E36D1A08-F3ED-48C7-9DBF-8F625974A6C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {E36D1A08-F3ED-48C7-9DBF-8F625974A6C4}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -917,22 +937,38 @@ Global {68C7FF71-54F6-4D68-B419-65D1B10206D4}.Release|x64.Build.0 = Release|Any CPU {68C7FF71-54F6-4D68-B419-65D1B10206D4}.Release|x86.ActiveCfg = Release|Any CPU {68C7FF71-54F6-4D68-B419-65D1B10206D4}.Release|x86.Build.0 = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|ARM.ActiveCfg = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|ARM.Build.0 = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x64.ActiveCfg = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x64.Build.0 = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x86.ActiveCfg = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Debug|x86.Build.0 = Debug|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|Any CPU.Build.0 = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|ARM.ActiveCfg = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|ARM.Build.0 = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x64.ActiveCfg = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x64.Build.0 = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x86.ActiveCfg = Release|Any CPU - {CA03FD55-9DAB-4827-9A35-A96D3804B311}.Release|x86.Build.0 = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|ARM.Build.0 = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|x64.ActiveCfg = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|x64.Build.0 = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|x86.ActiveCfg = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Debug|x86.Build.0 = Debug|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|Any CPU.Build.0 = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|ARM.ActiveCfg = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|ARM.Build.0 = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|x64.ActiveCfg = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|x64.Build.0 = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|x86.ActiveCfg = Release|Any CPU + {D8368319-F370-4071-9411-A3DADB234330}.Release|x86.Build.0 = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|ARM.Build.0 = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|x64.Build.0 = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Debug|x86.Build.0 = Debug|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|Any CPU.Build.0 = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|ARM.ActiveCfg = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|ARM.Build.0 = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|x64.ActiveCfg = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|x64.Build.0 = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|x86.ActiveCfg = Release|Any CPU + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -982,10 +1018,12 @@ Global {9000129D-322D-4FE6-9C47-75464577C374} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F} {ABB1BF71-8927-49BB-99F3-70BCB2CD161E} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38} {51074A4C-15C2-4E72-81F2-2FC53903553B} = {122BC4FA-7563-4E35-9D17-077F16F1629F} + {CA03FD55-9DAB-4827-9A35-A96D3804B311} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} {E36D1A08-F3ED-48C7-9DBF-8F625974A6C4} = {BCA2A024-9032-4E56-A6C4-17A15D921728} {9E0D0994-7D84-40FF-8383-189F142FEF11} = {BCA2A024-9032-4E56-A6C4-17A15D921728} {68C7FF71-54F6-4D68-B419-65D1B10206D4} = {BCA2A024-9032-4E56-A6C4-17A15D921728} - {CA03FD55-9DAB-4827-9A35-A96D3804B311} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} + {D8368319-F370-4071-9411-A3DADB234330} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} + {B01B327C-FC68-49B6-BDE3-A13D0C66DF5C} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20} diff --git a/src-console/ConsoleAppEF6_InMemory/ConsoleApp_net6.0_EF6_InMemory.csproj b/src-console/ConsoleAppEF6_InMemory/ConsoleApp_net6.0_EF6_InMemory.csproj index ae146c55..bdda14c6 100644 --- a/src-console/ConsoleAppEF6_InMemory/ConsoleApp_net6.0_EF6_InMemory.csproj +++ b/src-console/ConsoleAppEF6_InMemory/ConsoleApp_net6.0_EF6_InMemory.csproj @@ -3,7 +3,7 @@ Exe net6.0 - 10 + 12 enable diff --git a/src-console/ConsoleAppEF6_Sqlite/ConsoleApp_net6.0_EF6_Sqlite.csproj b/src-console/ConsoleAppEF6_Sqlite/ConsoleApp_net6.0_EF6_Sqlite.csproj index acb04590..8882c3f8 100644 --- a/src-console/ConsoleAppEF6_Sqlite/ConsoleApp_net6.0_EF6_Sqlite.csproj +++ b/src-console/ConsoleAppEF6_Sqlite/ConsoleApp_net6.0_EF6_Sqlite.csproj @@ -3,7 +3,7 @@ Exe net6.0 - 10 + 12 enable diff --git a/src-console/ConsoleApp_net452_EF6/Program.cs b/src-console/ConsoleApp_net452_EF6/Program.cs index 8c59c767..56bd91c9 100644 --- a/src-console/ConsoleApp_net452_EF6/Program.cs +++ b/src-console/ConsoleApp_net452_EF6/Program.cs @@ -9,13 +9,16 @@ class Program { static void Main(string[] args) { - using (var context = new KendoGridDbContext()) + var config = new ParsingConfig { - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = true - }; + UseParameterizedNamesInDynamicQuery = true + }; + + var q = new[] { 1, 2, 3 }.AsQueryable(); + var r = q.Where("it > 1").ToArray(); + using (var context = new KendoGridDbContext()) + { var found1 = context.Employees.FirstOrDefault(config, "EmployeeNumber > 1000"); Console.WriteLine($"found1 : {found1.Id} - {found1.EmployeeNumber}"); diff --git a/src-console/Demo.Host/Demo.Host.csproj b/src-console/Demo.Host/Demo.Host.csproj new file mode 100644 index 00000000..a06d6724 --- /dev/null +++ b/src-console/Demo.Host/Demo.Host.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src-console/Demo.Host/Program.cs b/src-console/Demo.Host/Program.cs new file mode 100644 index 00000000..370515a1 --- /dev/null +++ b/src-console/Demo.Host/Program.cs @@ -0,0 +1,66 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Dynamic.Core; +using System.Reflection; +using Serilog; +using Serilog.Exceptions; + +AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve; + +Log.Logger = new LoggerConfiguration() + .Enrich.WithExceptionDetails() + .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}") + .CreateLogger(); + +var customers = new List +{ + new(Guid.NewGuid(), [ + new Order(Guid.NewGuid()), + new Order(Guid.NewGuid()), + new Order(Guid.NewGuid()), + new Order(Guid.NewGuid()) + ]), + new(Guid.NewGuid(), [ + new Order(Guid.NewGuid()), + new Order(Guid.NewGuid()) + ]) +}; + +Log.Information("--- LoadAdditionalAssembliesFromCurrentDomainBaseDirectory = {load} ---", false); +var result = customers + .AsQueryable() + .Where("Orders.Count >= @0", 3) + .OrderBy("Orders.Count") + .ToList(); +Log.Information("Found {Count} customers: {Customers}", result.Count, result); + +Log.Information(new string('*', 80)); + +Log.Information("--- LoadAdditionalAssembliesFromCurrentDomainBaseDirectory = {load} ---", true); +var config = new ParsingConfig +{ + LoadAdditionalAssembliesFromCurrentDomainBaseDirectory = true +}; +var result2 = customers + .AsQueryable() + .Where(config, "Orders.Count >= @0", 3) + .OrderBy("Orders.Count") + .ToList(); +Log.Information("Found {Count} customers: {Customers}", result2.Count, result2); + +return; + +static Assembly? CurrentDomainOnAssemblyResolve(object? sender, ResolveEventArgs resolveEventArgs) +{ + Log.Warning("Attempted to resolve assembly {Name} by {RequestingAssembly}", resolveEventArgs.Name, resolveEventArgs.RequestingAssembly?.GetName().Name); + + return null; +} + +[SuppressMessage("Design", "CA1050:Declare types in namespaces")] +[SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Global")] +public record Order(Guid Id); + +[SuppressMessage("Design", "CA1050:Declare types in namespaces")] +[SuppressMessage("ReSharper", "NotAccessedPositionalProperty.Global")] +public record Customer(Guid Id, List Orders); \ No newline at end of file diff --git a/src-console/Demo.Plugin/Demo.Plugin.csproj b/src-console/Demo.Plugin/Demo.Plugin.csproj new file mode 100644 index 00000000..ca0a7eb1 --- /dev/null +++ b/src-console/Demo.Plugin/Demo.Plugin.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + enable + enable + + + + + + + \ No newline at end of file diff --git a/src-console/Demo.Plugin/MyPlugin.cs b/src-console/Demo.Plugin/MyPlugin.cs new file mode 100644 index 00000000..b25a8f1d --- /dev/null +++ b/src-console/Demo.Plugin/MyPlugin.cs @@ -0,0 +1,9 @@ +namespace Demo.Plugin; + +public static class MyPlugin +{ + public static void Print() + { + Console.WriteLine("Hello, World!"); + } +} \ No newline at end of file diff --git a/src-console/build.ps1 b/src-console/build.ps1 new file mode 100644 index 00000000..6dc2bfd2 --- /dev/null +++ b/src-console/build.ps1 @@ -0,0 +1,15 @@ +if (Test-Path -Path ".\output") { + Remove-Item -Force -Recurse -Path ".\output\" +} +else { + New-Item -Path ".\output" -ItemType Directory +} + + +Write-Host "Build solution..." + +dotnet build .\LinqCoreDemo.sln --nologo --configuration "Debug" + +Write-Host "Publish projects..." +dotnet publish .\src\Demo.Plugin\Demo.Plugin.csproj --nologo --no-build --configuration "Debug" --output .\output +dotnet publish .\src\Demo.Host\Demo.Host.csproj --nologo --no-build --configuration "Debug" --output .\output diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e34f3e2a..5a36e122 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ Copyright © ZZZ Projects en-us true - latest + 12 enable logo.png PackageReadme.md diff --git a/src/EntityFramework.DynamicLinq/EFType.cs b/src/EntityFramework.DynamicLinq/EFType.cs new file mode 100644 index 00000000..0fa458a2 --- /dev/null +++ b/src/EntityFramework.DynamicLinq/EFType.cs @@ -0,0 +1,8 @@ +namespace EntityFramework.DynamicLinq; + +/// +/// A dummy class to determine if the assembly is using EntityFramework. +/// +public struct EFType +{ +} \ No newline at end of file diff --git a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj index 228f2cab..f42d3a3c 100644 --- a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj +++ b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj @@ -10,7 +10,6 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E510000} net45;net452;net46;netstandard2.1 - 10 1.3.$(PatchVersion) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.AppVeyor.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.AppVeyor.csproj deleted file mode 100644 index b5b10b37..00000000 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.AppVeyor.csproj +++ /dev/null @@ -1,113 +0,0 @@ - - - Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support - Microsoft.EntityFrameworkCore.DynamicLinq - 1.0.8.12 - Stef Heyenrath - net451;net46;netstandard1.3;netstandard2.0 - $(DefineConstants);EFCORE - true - Microsoft.EntityFrameworkCore.DynamicLinq - Microsoft.EntityFrameworkCore.DynamicLinq.snk - true - true - system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see the release notes. - https://github.com/StefH/System.Linq.Dynamic.Core - https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/licence.txt - git - https://github.com/StefH/System.Linq.Dynamic.Core - $(PackageTargetFallback);dotnet5.4;portable-win81+wp81;portable-net45+wp8;portable-net45+win8+wp8;portable-wp81+wpa81;portable-win81+wp81+wpa81;portable-net45+win8+wpa81+wp8;portable-net45+win8;portable-net45+win8+wpa81;portable-win81+wpa81;portable-net451+win81;portable-net451+win81+wpa81 - false - false - false - false - false - false - false - en-us - {D3804228-91F4-4502-9595-39584E510001} - full - - - - True - True - $(MSBuildProjectDirectory)=/ - true - - - - false - UAP,Version=v10.0 - UAP - 10.0.14393.0 - 10.0.10240.0 - .NETCore - v5.0 - $(DefineConstants);WINDOWS_UWP;UAP10_0 - $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - - - - $(DefineConstants);NETSTANDARD - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj index 5ee194b9..52ed170e 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj @@ -10,7 +10,6 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E510001} netstandard2.0 - 10 2.3.$(PatchVersion) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFCoreType.cs b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFCoreType.cs new file mode 100644 index 00000000..d2d82539 --- /dev/null +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFCoreType.cs @@ -0,0 +1,8 @@ +namespace Microsoft.EntityFrameworkCore.DynamicLinq; + +/// +/// A dummy class to determine if the assembly is using EF Core. +/// +public struct EFCoreType +{ +} \ No newline at end of file diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj index 39ab2271..8b7d9c12 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj @@ -10,7 +10,6 @@ system;linq;dynamic;entityframework;core;async {7994FECC-965C-4A5D-8B0E-1A6EA769D4BE} netstandard2.0 - 10 3.3.$(PatchVersion) @@ -43,9 +42,6 @@ - - - diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj index be78d065..37ed5bfa 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj @@ -10,7 +10,6 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E519901} netstandard2.1;net5.0 - 10 5.3.$(PatchVersion) diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs index 421ec713..fc58ec0f 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs @@ -3,107 +3,108 @@ using System.Reflection; using System.Runtime.CompilerServices; -namespace System.Linq.Dynamic.Core.CustomTypeProviders +namespace System.Linq.Dynamic.Core.CustomTypeProviders; + +/// +/// The default implementation for . +/// +/// Scans the current AppDomain for all types marked with , 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 and .NET Core App 2.x and higher. +/// +public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider { + private readonly IAssemblyHelper _assemblyHelper; + private readonly bool _cacheCustomTypes; + + private HashSet? _cachedCustomTypes; + private Dictionary>? _cachedExtensionMethods; + /// - /// The default implementation for . - /// - /// Scans the current AppDomain for all types marked with , 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 + /// Initializes a new instance of the class. /// - public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider + /// The parsing configuration. + /// Defines whether to cache the CustomTypes (including extension methods) which are found in the Application Domain. Default set to 'true'. + public DefaultDynamicLinqCustomTypeProvider(ParsingConfig config, bool cacheCustomTypes = true) { - private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper(); - private readonly bool _cacheCustomTypes; - - private HashSet? _cachedCustomTypes; - private Dictionary>? _cachedExtensionMethods; - - /// - /// Initializes a new instance of the class. - /// - /// Defines whether to cache the CustomTypes (including extension methods) which are found in the Application Domain. Default set to 'true'. - public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true) - { - _cacheCustomTypes = cacheCustomTypes; - } + _assemblyHelper = new DefaultAssemblyHelper(config); + _cacheCustomTypes = cacheCustomTypes; + } - /// - public virtual HashSet GetCustomTypes() + /// + public virtual HashSet GetCustomTypes() + { + if (_cacheCustomTypes) { - if (_cacheCustomTypes) + if (_cachedCustomTypes == null) { - if (_cachedCustomTypes == null) - { - _cachedCustomTypes = GetCustomTypesInternal(); - } - - return _cachedCustomTypes; + _cachedCustomTypes = GetCustomTypesInternal(); } - return GetCustomTypesInternal(); + return _cachedCustomTypes; } - /// - public Dictionary> GetExtensionMethods() + return GetCustomTypesInternal(); + } + + /// + public Dictionary> GetExtensionMethods() + { + if (_cacheCustomTypes) { - if (_cacheCustomTypes) + if (_cachedExtensionMethods == null) { - if (_cachedExtensionMethods == null) - { - _cachedExtensionMethods = GetExtensionMethodsInternal(); - } - - return _cachedExtensionMethods; + _cachedExtensionMethods = GetExtensionMethodsInternal(); } - return GetExtensionMethodsInternal(); + return _cachedExtensionMethods; } - /// - public Type? ResolveType(string typeName) - { - Check.NotEmpty(typeName); + return GetExtensionMethodsInternal(); + } - IEnumerable assemblies = _assemblyHelper.GetAssemblies(); - return ResolveType(assemblies, typeName); - } + /// + public Type? ResolveType(string typeName) + { + Check.NotEmpty(typeName); - /// - public Type? ResolveTypeBySimpleName(string simpleTypeName) - { - Check.NotEmpty(simpleTypeName); + IEnumerable assemblies = _assemblyHelper.GetAssemblies(); + return ResolveType(assemblies, typeName); + } - IEnumerable assemblies = _assemblyHelper.GetAssemblies(); - return ResolveTypeBySimpleName(assemblies, simpleTypeName); - } + /// + public Type? ResolveTypeBySimpleName(string simpleTypeName) + { + Check.NotEmpty(simpleTypeName); - private HashSet GetCustomTypesInternal() - { - IEnumerable assemblies = _assemblyHelper.GetAssemblies(); - return new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies)); - } + IEnumerable assemblies = _assemblyHelper.GetAssemblies(); + return ResolveTypeBySimpleName(assemblies, simpleTypeName); + } - private Dictionary> GetExtensionMethodsInternal() - { - var types = GetCustomTypes(); + private HashSet GetCustomTypesInternal() + { + IEnumerable assemblies = _assemblyHelper.GetAssemblies(); + return new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies)); + } - var list = new List>(); + private Dictionary> GetExtensionMethodsInternal() + { + var types = GetCustomTypes(); - foreach (var type in types) - { - var extensionMethods = type - .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) - .Where(x => x.IsDefined(typeof(ExtensionAttribute), false)) - .ToList(); + var list = new List>(); - extensionMethods.ForEach(x => list.Add(new Tuple(x.GetParameters()[0].ParameterType, x))); - } + foreach (var type in types) + { + var extensionMethods = type + .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + .Where(x => x.IsDefined(typeof(ExtensionAttribute), false)) + .ToList(); - return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); + extensionMethods.ForEach(x => list.Add(new Tuple(x.GetParameters()[0].ParameterType, x))); } + + return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); } } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DefaultAssemblyHelper.cs b/src/System.Linq.Dynamic.Core/DefaultAssemblyHelper.cs index cc159964..0dcabe16 100644 --- a/src/System.Linq.Dynamic.Core/DefaultAssemblyHelper.cs +++ b/src/System.Linq.Dynamic.Core/DefaultAssemblyHelper.cs @@ -1,11 +1,14 @@ using System.IO; using System.Reflection; using System.Collections.Generic; +using System.Linq.Dynamic.Core.Validation; namespace System.Linq.Dynamic.Core; -internal class DefaultAssemblyHelper : IAssemblyHelper +internal class DefaultAssemblyHelper(ParsingConfig parsingConfig) : IAssemblyHelper { + private readonly ParsingConfig _config = Check.NotNull(parsingConfig); + public Assembly[] GetAssemblies() { #if WINDOWS_APP || UAP10_0 || NETSTANDARD || WPSL @@ -31,6 +34,11 @@ public Assembly[] GetAssemblies() } } + if (!_config.LoadAdditionalAssembliesFromCurrentDomainBaseDirectory) + { + return loadedAssemblies.ToArray(); + } + string[] referencedPaths; try { @@ -38,10 +46,12 @@ public Assembly[] GetAssemblies() } catch { - referencedPaths = new string[0]; + referencedPaths = []; } - var pathsToLoad = referencedPaths.Where(referencedPath => !loadedPaths.Contains(referencedPath, StringComparer.InvariantCultureIgnoreCase)); + var pathsToLoad = referencedPaths + .Where(referencedPath => !loadedPaths.Contains(referencedPath, StringComparer.InvariantCultureIgnoreCase)) + .ToArray(); foreach (var path in pathsToLoad) { try diff --git a/src/System.Linq.Dynamic.Core/Parser/KeywordsHelper.cs b/src/System.Linq.Dynamic.Core/Parser/KeywordsHelper.cs index b6e852d1..2fa4ffdf 100644 --- a/src/System.Linq.Dynamic.Core/Parser/KeywordsHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/KeywordsHelper.cs @@ -46,7 +46,7 @@ internal class KeywordsHelper : IKeywordsHelper }; // PreDefined Types are not IgnoreCase - private static readonly Dictionary _preDefinedTypeMapping = new(); + private static readonly Dictionary PreDefinedTypeMapping = new(); // Custom DefinedTypes are not IgnoreCase private readonly Dictionary _customTypeMapping = new(); @@ -55,8 +55,8 @@ static KeywordsHelper() { foreach (var type in PredefinedTypesHelper.PredefinedTypes.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key)) { - _preDefinedTypeMapping[type.FullName!] = type; - _preDefinedTypeMapping[type.Name] = type; + PreDefinedTypeMapping[type.FullName!] = type; + PreDefinedTypeMapping[type.Name] = type; } } @@ -99,7 +99,7 @@ public bool TryGetValue(string name, [NotNullWhen(true)] out object? keyWordOrTy } // 3. Try to get as predefined type ("Boolean", "System.Boolean", ..., "DateTime", "System.DateTime", ...) - if (_preDefinedTypeMapping.TryGetValue(name, out var predefinedType)) + if (PreDefinedTypeMapping.TryGetValue(name, out var predefinedType)) { keyWordOrType = predefinedType; return true; diff --git a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs index 2e37d57d..58cb5f64 100644 --- a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs @@ -6,10 +6,6 @@ namespace System.Linq.Dynamic.Core.Parser; internal static class PredefinedTypesHelper { -#if NETSTANDARD2_0 - private static readonly string Version = Text.RegularExpressions.Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName!, @"\d+\.\d+\.\d+\.\d+").ToString(); -#endif - // These shorthands have different name than actual type and therefore not recognized by default from the PredefinedTypes. public static readonly IDictionary PredefinedTypesShorthands = new Dictionary { @@ -27,10 +23,10 @@ internal static class PredefinedTypesHelper { "string", typeof(string) }, { "uint", typeof(uint) }, { "ulong", typeof(ulong) }, - { "ushort", typeof(ushort) }, + { "ushort", typeof(ushort) } }; - public static readonly IDictionary PredefinedTypes = new ConcurrentDictionary(new Dictionary + public static readonly IDictionary PredefinedTypes = new ConcurrentDictionary(new Dictionary { { typeof(object), 0 }, { typeof(bool), 0 }, @@ -63,24 +59,29 @@ internal static class PredefinedTypesHelper static PredefinedTypesHelper() { -#if !(NET35 || SILVERLIGHT || NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) - //System.Data.Entity is always here, so overwrite short name of it with EntityFramework if EntityFramework is found. - //EF5(or 4.x??), System.Data.Objects.DataClasses.EdmFunctionAttribute - //There is also an System.Data.Entity, Version=3.5.0.0, but no Functions. - TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - - //EF6,System.Data.Entity.DbFunctionAttribute - TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + // Only add these types for full .NET Framework and .NETStandard 2.1 + // And only if the EntityFramework.DynamicLinq is available. +#if NET452_OR_GREATER || NETSTANDARD2_1 + if (Type.GetType("EntityFramework.DynamicLinq.EFType, EntityFramework.DynamicLinq") != null) + { + TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + } #endif -#if NETSTANDARD2_0 - TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={Version}, Culture=neutral, PublicKeyToken=974e7e1b462f3693", 3); +#if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER + const string publicKeyToken = "974e7e1b462f3693"; + var version = Text.RegularExpressions.Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName!, @"\d+\.\d+\.\d+\.\d+").ToString(); + if (Type.GetType($"Microsoft.EntityFrameworkCore.DynamicLinq.EFType, Microsoft.EntityFrameworkCore.DynamicLinq, Version={version}, Culture=neutral, PublicKeyToken={publicKeyToken}") != null) + { + TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={version}, Culture=neutral, PublicKeyToken={publicKeyToken}", 3); + } #endif } @@ -88,15 +89,15 @@ private static void TryAdd(string typeName, int x) { try { - var efType = Type.GetType(typeName); - if (efType != null) + var type = Type.GetType(typeName); + if (type != null) { - PredefinedTypes.Add(efType, x); + PredefinedTypes.Add(type, x); } } catch { - // in case of exception, do not add + // In case of exception, do not add } } @@ -111,7 +112,6 @@ public static bool IsPredefinedType(ParsingConfig config, Type type) return true; } - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract return config.CustomTypeProvider != null && (config.CustomTypeProvider.GetCustomTypes().Contains(type) || config.CustomTypeProvider.GetCustomTypes().Contains(nonNullableType)); } diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index 5378dc1a..8d151a76 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -113,7 +113,7 @@ public int FindMethod(Type? type, string methodName, bool staticAccess, ref Expr } #endif - if (instance != null) + if (instance != null && _parsingConfig.CustomTypeProvider != null) { // Try to solve with registered extension methods from this type and all base types var methods = new List(); diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index ec3a164a..f8fbc194 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -12,6 +12,10 @@ namespace System.Linq.Dynamic.Core; /// public class ParsingConfig { + private IDynamicLinkCustomTypeProvider? _customTypeProvider; + private IExpressionPromoter? _expressionPromoter; + private IQueryableAnalyzer? _queryableAnalyzer; + /// /// Default ParsingConfig /// @@ -25,9 +29,6 @@ public class ParsingConfig EvaluateGroupByAtDatabase = true }; - /// Gets or sets if parameter, method, and properties resolution should be case sensitive or not (false by default). - public bool IsCaseSensitive { get; set; } - /// /// Default ParsingConfig for CosmosDb /// @@ -36,44 +37,47 @@ public class ParsingConfig RenameEmptyParameterExpressionNames = true }; - private IDynamicLinkCustomTypeProvider? _customTypeProvider; - - private IExpressionPromoter? _expressionPromoter; - - private IQueryableAnalyzer? _queryableAnalyzer; + /// + /// Gets or sets if parameter, method, and properties resolution should be case-sensitive or not. + /// + /// Default value is false. + /// + public bool IsCaseSensitive { get; set; } /// /// Gets or sets the . /// - public IDynamicLinkCustomTypeProvider CustomTypeProvider + public IDynamicLinkCustomTypeProvider? CustomTypeProvider { get { -#if !( WINDOWS_APP || UAP10_0 || NETSTANDARD) - // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and NET Core App 2.x - return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(); +#if !(WINDOWS_APP || UAP10_0 || NETSTANDARD) + // Only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and .NET Core App 2.x and higher. + return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(this); #else return _customTypeProvider; #endif } - set { - // ReSharper disable once RedundantCheckBeforeAssignment - if (_customTypeProvider != value) - { - _customTypeProvider = value; - } + _customTypeProvider = value; } } + /// + /// Load additional assemblies from the current domain base directory. + /// Note: only used when full .NET Framework and .NET Core App 2.x and higher. + /// + /// Default value is false. + /// + public bool LoadAdditionalAssembliesFromCurrentDomainBaseDirectory { get; set; } + /// /// Gets or sets the . /// public IExpressionPromoter ExpressionPromoter { get => _expressionPromoter ??= new ExpressionPromoter(this); - set { // ReSharper disable once RedundantCheckBeforeAssignment @@ -93,7 +97,6 @@ public IQueryableAnalyzer QueryableAnalyzer { return _queryableAnalyzer ??= new DefaultQueryableAnalyzer(); } - set { // ReSharper disable once RedundantCheckBeforeAssignment @@ -115,8 +118,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. /// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation - /// - /// Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. + /// Remark: when this setting is set to true, make sure to supply this ParsingConfig as first parameter on the extension methods. /// /// Default value is false. /// @@ -128,21 +130,21 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool UseParameterizedNamesInDynamicQuery { get; set; } = false; + public bool UseParameterizedNamesInDynamicQuery { get; set; } /// /// Allows the New() keyword to evaluate any available Type. /// /// Default value is false. /// - public bool AllowNewToEvaluateAnyType { get; set; } = false; + public bool AllowNewToEvaluateAnyType { get; set; } /// - /// Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from `it`. + /// Renames the (Typed)ParameterExpression empty Name to the correct supplied name from `it`. /// /// Default value is false. /// - public bool RenameParameterExpression { get; set; } = false; + public bool RenameParameterExpression { get; set; } /// /// Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word. @@ -152,37 +154,36 @@ public IQueryableAnalyzer QueryableAnalyzer public bool RenameEmptyParameterExpressionNames { get; set; } /// - /// By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use - /// this flag to disable this behaviour and have parsing fail when parsing an expression - /// where a member access on a non existing member happens. + /// By default, when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. + /// Use this flag to disable this behaviour and have parsing fail when parsing an expression where a member access on a non-existing member happens. /// /// Default value is false. /// - public bool DisableMemberAccessToIndexAccessorFallback { get; set; } = false; + public bool DisableMemberAccessToIndexAccessorFallback { get; set; } /// - /// By default finding types by a simple name is not supported. + /// By default, finding types by a simple name is not supported. /// Use this flag to use the CustomTypeProvider to resolve types by a simple name like "Employee" instead of "MyDatabase.Entities.Employee". /// Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. /// /// Default value is false. /// - public bool ResolveTypesBySimpleName { get; set; } = false; + public bool ResolveTypesBySimpleName { get; set; } /// /// Support enumeration-types from the System namespace in mscorlib. An example could be "StringComparison". /// - /// Default value is true. + /// Default value is true. /// public bool SupportEnumerationsFromSystemNamespace { get; set; } = true; /// - /// By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. + /// By default, a DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. /// Use this flag to parse all DateTime strings as UTC. /// /// Default value is false. /// - public bool DateTimeIsParsedAsUTC { get; set; } = false; + public bool DateTimeIsParsedAsUTC { get; set; } /// /// The number parsing culture. @@ -201,10 +202,10 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } = false; + public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } /// - /// Support casting to a full qualified type using a string (double quoted value). + /// Support casting to a full qualified type using a string (double-quoted value). /// /// var result = queryable.Select($"\"System.DateTime\"(LastUpdate)"); /// @@ -215,7 +216,6 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// When the type and property have the same name the parser takes the property instead of type when this setting is set to true. - /// /// This setting is also used for calling ExtensionMethods. /// /// Default value is true. @@ -227,14 +227,14 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool SupportDotInPropertyNames { get; set; } = false; + public bool SupportDotInPropertyNames { get; set; } /// /// Disallows the New() keyword to be used to construct a class. /// /// Default value is false. /// - public bool DisallowNewKeyword { get; set; } = false; + public bool DisallowNewKeyword { get; set; } /// /// Caches constant expressions to enhance performance. Periodic cleanup is performed to manage cache size, governed by this configuration. diff --git a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj index 2489fcb4..ada7fb18 100644 --- a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj +++ b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj @@ -10,7 +10,6 @@ system;linq;dynamic;Z.EntityFramework;core;async;classic {D3804228-91F4-4502-9595-39584Ea20000} net45;netstandard2.0 - 10 1.3.$(PatchVersion) diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 00000000..8523fee1 --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,5 @@ + + + 12 + + diff --git a/test/System.Linq.Dynamic.Core.Tests/DefaultDynamicLinqCustomTypeProviderTests.cs b/test/System.Linq.Dynamic.Core.Tests/DefaultDynamicLinqCustomTypeProviderTests.cs index 9a2f6674..1c9fe130 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DefaultDynamicLinqCustomTypeProviderTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DefaultDynamicLinqCustomTypeProviderTests.cs @@ -4,55 +4,54 @@ using NFluent; using Xunit; -namespace System.Linq.Dynamic.Core.Tests +namespace System.Linq.Dynamic.Core.Tests; + +public class DefaultDynamicLinqCustomTypeProviderTests { - public class DefaultDynamicLinqCustomTypeProviderTests + private readonly IDynamicLinkCustomTypeProvider _sut; + + public DefaultDynamicLinqCustomTypeProviderTests() + { + _sut = new DefaultDynamicLinqCustomTypeProvider(ParsingConfig.Default); + } + + [Fact] + public void DefaultDynamicLinqCustomTypeProvider_ResolveSystemType() + { + // Act + var type = _sut.ResolveType(typeof(DirectoryInfo).FullName); + + // Assert + type.Should().Be(typeof(DirectoryInfo)); + } + + [Fact] + public void DefaultDynamicLinqCustomTypeProvider_GetCustomTypes() { - private readonly IDynamicLinkCustomTypeProvider _sut; - - public DefaultDynamicLinqCustomTypeProviderTests() - { - _sut = new DefaultDynamicLinqCustomTypeProvider(); - } - - [Fact] - public void DefaultDynamicLinqCustomTypeProvider_ResolveSystemType() - { - // Act - var type = _sut.ResolveType(typeof(DirectoryInfo).FullName); - - // Assert - type.Should().Be(typeof(DirectoryInfo)); - } - - [Fact] - public void DefaultDynamicLinqCustomTypeProvider_GetCustomTypes() - { - // Act - var types = _sut.GetCustomTypes(); - - // Assert - Check.That(types.Count).IsStrictlyGreaterThan(0); - } - - [Fact] - public void DefaultDynamicLinqCustomTypeProvider_ResolveType_UnknownReturnsNull() - { - // Act - var result = _sut.ResolveType("dummy"); - - // Assert - Check.That(result).IsNull(); - } - - [Fact] - public void DefaultDynamicLinqCustomTypeProvider_ResolveType_DefinedReturnsType() - { - // Act - var result = _sut.ResolveType(typeof(DefaultDynamicLinqCustomTypeProviderTests).FullName); - - // Assert - Check.That(result).IsNotNull(); - } + // Act + var types = _sut.GetCustomTypes(); + + // Assert + Check.That(types.Count).IsStrictlyGreaterThan(0); + } + + [Fact] + public void DefaultDynamicLinqCustomTypeProvider_ResolveType_UnknownReturnsNull() + { + // Act + var result = _sut.ResolveType("dummy"); + + // Assert + Check.That(result).IsNull(); + } + + [Fact] + public void DefaultDynamicLinqCustomTypeProvider_ResolveType_DefinedReturnsType() + { + // Act + var result = _sut.ResolveType(typeof(DefaultDynamicLinqCustomTypeProviderTests).FullName); + + // Assert + Check.That(result).IsNotNull(); } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index d03cd692..d95fa00e 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -55,7 +55,7 @@ public void Bar() public MyClass Child { get; set; } } - private class MyClassCustomTypeProvider : DefaultDynamicLinqCustomTypeProvider + private class MyClassCustomTypeProvider() : DefaultDynamicLinqCustomTypeProvider(ParsingConfig.Default) { public override HashSet GetCustomTypes() { @@ -2113,7 +2113,7 @@ public void DynamicExpressionParser_ParseLambda_LambdaParameter_SameNameAsDynami DynamicExpressionParser.ParseLambda(new ParsingConfig(), false, "new[]{1,2,3}.Any(z => z > 0)"); } - public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : DefaultDynamicLinqCustomTypeProvider + public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod() : DefaultDynamicLinqCustomTypeProvider(ParsingConfig.Default) { public override HashSet GetCustomTypes() => new HashSet(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; } diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs index 0c51ea52..a540d558 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs @@ -20,7 +20,7 @@ private static ParsingConfig CreateParsingConfigForMethodCallTests() }; } - private class DefaultDynamicLinqCustomTypeProviderForStaticTesting : DefaultDynamicLinqCustomTypeProvider + private class DefaultDynamicLinqCustomTypeProviderForStaticTesting() : DefaultDynamicLinqCustomTypeProvider(ParsingConfig.Default) { public override HashSet GetCustomTypes() => new(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; } diff --git a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj index 3a27dfd4..527007e6 100644 --- a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj +++ b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj @@ -5,7 +5,6 @@ System.Linq.Dynamic.Core.Tests full True - latest enable ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk {912FBF24-3CAE-4A50-B5EA-E525B9FAEC80}