Skip to content

Commit 1396110

Browse files
committed
EvaluateGroupByAtDatabase (#165)
1 parent 5863256 commit 1396110

File tree

11 files changed

+235
-15
lines changed

11 files changed

+235
-15
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ The following frameworks are supported:
4040
- net45 and up
4141
- netstandard1.3
4242
- netstandard2.0
43-
- uap10.0
43+
- uap10.0 (TODO...)s
4444

4545
## Fork details
4646
This fork takes the basic library to a new level. Contains XML Documentation and examples on how to use it. Also adds unit testing to help ensure that it works properly.

System.Linq.Dynamic.Core.sln

+19
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp_netcore2.0_EF2.0
5353
EndProject
5454
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemoryLeakTest167", "src-console\MemoryLeakTest167\MemoryLeakTest167.csproj", "{AD4F83E5-4240-485D-BB5C-F43974F716E4}"
5555
EndProject
56+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp_netcore2.0_EF2.1", "src-console\ConsoleAppEF2.1\ConsoleApp_netcore2.0_EF2.1.csproj", "{EDF434F6-70C0-4005-B63E-0C365B3DA42A}"
57+
EndProject
5658
Global
5759
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5860
Debug|Any CPU = Debug|Any CPU
@@ -287,6 +289,22 @@ Global
287289
{AD4F83E5-4240-485D-BB5C-F43974F716E4}.Release|x64.Build.0 = Release|Any CPU
288290
{AD4F83E5-4240-485D-BB5C-F43974F716E4}.Release|x86.ActiveCfg = Release|Any CPU
289291
{AD4F83E5-4240-485D-BB5C-F43974F716E4}.Release|x86.Build.0 = Release|Any CPU
292+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
293+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
294+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|ARM.ActiveCfg = Debug|Any CPU
295+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|ARM.Build.0 = Debug|Any CPU
296+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|x64.ActiveCfg = Debug|Any CPU
297+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|x64.Build.0 = Debug|Any CPU
298+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|x86.ActiveCfg = Debug|Any CPU
299+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Debug|x86.Build.0 = Debug|Any CPU
300+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|Any CPU.ActiveCfg = Release|Any CPU
301+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|Any CPU.Build.0 = Release|Any CPU
302+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|ARM.ActiveCfg = Release|Any CPU
303+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|ARM.Build.0 = Release|Any CPU
304+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|x64.ActiveCfg = Release|Any CPU
305+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|x64.Build.0 = Release|Any CPU
306+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|x86.ActiveCfg = Release|Any CPU
307+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A}.Release|x86.Build.0 = Release|Any CPU
290308
EndGlobalSection
291309
GlobalSection(SolutionProperties) = preSolution
292310
HideSolutionNode = FALSE
@@ -306,6 +324,7 @@ Global
306324
{5DC68E83-ABE0-4887-B17E-1ED4EEE89C2C} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
307325
{437473EE-7FBB-4C28-96EC-41E1AEE161F3} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
308326
{AD4F83E5-4240-485D-BB5C-F43974F716E4} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
327+
{EDF434F6-70C0-4005-B63E-0C365B3DA42A} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
309328
EndGlobalSection
310329
GlobalSection(ExtensibilityGlobals) = postSolution
311330
SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.0</TargetFramework>
6+
<AssemblyName>ConsoleAppEF21</AssemblyName>
7+
<RootNamespace>ConsoleAppEF21</RootNamespace>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.1.1" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
13+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
14+
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\..\src\System.Linq.Dynamic.Core\System.Linq.Dynamic.Core.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace ConsoleAppEF21.Database
4+
{
5+
public class Car
6+
{
7+
[Key]
8+
public int Key { get; set; }
9+
10+
[Required]
11+
[StringLength(8)]
12+
public string Vin { get; set; }
13+
14+
[Required]
15+
public string Year { get; set; }
16+
17+
[Required]
18+
public string Brand { get; set; }
19+
20+
[Required]
21+
public string Color { get; set; }
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.Extensions.Logging;
3+
using Microsoft.Extensions.Logging.Console;
4+
5+
namespace ConsoleAppEF21.Database
6+
{
7+
public class TestContext : DbContext
8+
{
9+
public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((filter, includeScopes) => true, true) });
10+
11+
public virtual DbSet<Car> Cars { get; set; }
12+
13+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
14+
{
15+
optionsBuilder.UseLoggerFactory(MyLoggerFactory); // Warning: Do not create a new ILoggerFactory instance each time
16+
optionsBuilder.EnableSensitiveDataLogging();
17+
18+
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=CarsEF20;Trusted_Connection=True;");
19+
}
20+
21+
protected override void OnModelCreating(ModelBuilder modelBuilder)
22+
{
23+
modelBuilder.Entity<Car>().HasKey(c => c.Key);
24+
}
25+
26+
// https://stackoverflow.com/questions/46212704/how-do-i-write-ef-functions-extension-method
27+
public static bool Like(string matchExpression, string pattern) => EF.Functions.Like(matchExpression, pattern);
28+
}
29+
}
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using System;
2+
using System.Linq;
3+
using System.Linq.Dynamic.Core;
4+
using ConsoleAppEF21.Database;
5+
using Newtonsoft.Json;
6+
7+
namespace ConsoleAppEF21
8+
{
9+
class Program
10+
{
11+
//class C : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
12+
//{
13+
// public HashSet<Type> GetCustomTypes()
14+
// {
15+
// var assemblies = AppDomain.CurrentDomain.GetAssemblies();
16+
17+
// var set = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies))
18+
// {
19+
// typeof(TestContext)
20+
// };
21+
22+
// return set;
23+
// }
24+
//}
25+
26+
//private static IQueryable GetQueryable()
27+
//{
28+
// var random = new Random((int)DateTime.Now.Ticks);
29+
30+
// var x = Enumerable.Range(0, 10).Select(i => new
31+
// {
32+
// Id = i,
33+
// Value = random.Next(),
34+
// });
35+
36+
// return x.AsQueryable().Select("new (it as Id, @0 as Value)", random.Next());
37+
// // return x.AsQueryable(); //x.AsQueryable().Select("new (Id, Value)");
38+
//}
39+
40+
static void Main(string[] args)
41+
{
42+
//IQueryable qry = GetQueryable();
43+
44+
//var result = qry.Select("it").OrderBy("Value");
45+
//try
46+
//{
47+
// Console.WriteLine("result {0}", JsonConvert.SerializeObject(result, Formatting.Indented));
48+
//}
49+
//catch (Exception)
50+
//{
51+
// // Console.WriteLine(e);
52+
//}
53+
54+
//var all = new
55+
//{
56+
// test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
57+
// test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
58+
// test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
59+
//};
60+
// Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.None));
61+
62+
var config = new ParsingConfig
63+
{
64+
EvaluateGroupByAtDatabase = true
65+
};
66+
67+
var context = new TestContext();
68+
if (!context.Cars.Any())
69+
{
70+
context.Cars.Add(new Car { Brand = "Ford", Color = "Blue", Vin = "yes", Year = "2017" });
71+
context.Cars.Add(new Car { Brand = "Fiat", Color = "Red", Vin = "yes", Year = "2016" });
72+
context.Cars.Add(new Car { Brand = "Alfa", Color = "Black", Vin = "no", Year = "1979" });
73+
context.Cars.Add(new Car { Brand = "Alfa", Color = "Black", Vin = "a%bc", Year = "1979" });
74+
context.SaveChanges();
75+
}
76+
77+
//var g1 = context.Cars.GroupBy("new(Brand)").Select("new(Key.Brand as KeyValue1, it.Count() as CountValue1)").ToDynamicList();
78+
//Console.WriteLine("GroupBy @ local {0}", JsonConvert.SerializeObject(g1, Formatting.Indented));
79+
80+
//Console.WriteLine(new string('_', 80));
81+
82+
var g2 = context.Cars.GroupBy("new(Brand)", config).Select("new(Key.Brand as KeyValue2, it.Count() as CountValue2)").ToDynamicList();
83+
Console.WriteLine("GroupBy @ database {0}", JsonConvert.SerializeObject(g2, Formatting.Indented));
84+
85+
//var carFirstOrDefault = context.Cars.Where(config, "Brand == \"Ford\"");
86+
//Console.WriteLine("carFirstOrDefault {0}", JsonConvert.SerializeObject(carFirstOrDefault, Formatting.Indented));
87+
88+
//var carsLike1 =
89+
// from c in context.Cars
90+
// where EF.Functions.Like(c.Brand, "%a%")
91+
// select c;
92+
//Console.WriteLine("carsLike1 {0}", JsonConvert.SerializeObject(carsLike1, Formatting.Indented));
93+
94+
//var cars2Like = context.Cars.Where(c => EF.Functions.Like(c.Brand, "%a%"));
95+
//Console.WriteLine("cars2Like {0}", JsonConvert.SerializeObject(cars2Like, Formatting.Indented));
96+
97+
//var dynamicCarsLike1 = context.Cars.Where(config, "TestContext.Like(Brand, \"%a%\")");
98+
//Console.WriteLine("dynamicCarsLike1 {0}", JsonConvert.SerializeObject(dynamicCarsLike1, Formatting.Indented));
99+
100+
//var dynamicCarsLike2 = context.Cars.Where(config, "TestContext.Like(Brand, \"%d%\")");
101+
//Console.WriteLine("dynamicCarsLike2 {0}", JsonConvert.SerializeObject(dynamicCarsLike2, Formatting.Indented));
102+
103+
//var dynamicFunctionsLike1 = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");
104+
//Console.WriteLine("dynamicFunctionsLike1 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike1, Formatting.Indented));
105+
106+
//var dynamicFunctionsLike2 = context.Cars.Where(config, "DynamicFunctions.Like(Vin, \"%a.%b%\", \".\")");
107+
//Console.WriteLine("dynamicFunctionsLike2 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike2, Formatting.Indented));
108+
109+
//var testDynamic = context.Cars.Select(c => new
110+
//{
111+
// K = c.Key,
112+
// C = c.Color
113+
//});
114+
115+
//var testDynamicResult = testDynamic.Select("it").OrderBy("C");
116+
//try
117+
//{
118+
// Console.WriteLine("resultX {0}", JsonConvert.SerializeObject(testDynamicResult, Formatting.Indented));
119+
//}
120+
//catch (Exception e)
121+
//{
122+
// Console.WriteLine(e);
123+
//}
124+
}
125+
}
126+
}

src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<SignAssembly>true</SignAssembly>
1313
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
1414
<PackageTags>system;linq;dynamic;entityframework;core;async</PackageTags>
15-
<PackageReleaseNotes>Bugfixes and new Features. For details see the release notes.</PackageReleaseNotes>
15+
<PackageReleaseNotes>Bugfixes and new Features. For details see CHANGELOG.md</PackageReleaseNotes>
1616
<PackageProjectUrl>https://github.com/StefH/System.Linq.Dynamic.Core</PackageProjectUrl>
1717
<PackageLicenseUrl>https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/licence.txt</PackageLicenseUrl>
1818
<RepositoryType>git</RepositoryType>
@@ -58,4 +58,4 @@
5858
<Reference Include="System" />
5959
<Reference Include="Microsoft.CSharp" />
6060
</ItemGroup>
61-
</Project>
61+
</Project>

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
<AssemblyTitle>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyTitle>
55
<VersionPrefix>1.0.8.11</VersionPrefix>
66
<Authors>Stef Heyenrath</Authors>
7-
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
7+
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
88
<DefineConstants>$(DefineConstants);EFCORE</DefineConstants>
99
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1010
<AssemblyName>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyName>
1111
<AssemblyOriginatorKeyFile>Microsoft.EntityFrameworkCore.DynamicLinq.snk</AssemblyOriginatorKeyFile>
1212
<SignAssembly>true</SignAssembly>
1313
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
1414
<PackageTags>system;linq;dynamic;entityframework;core;async</PackageTags>
15-
<PackageReleaseNotes>Bugfixes and new Features. For details see the release notes.</PackageReleaseNotes>
15+
<PackageReleaseNotes>Bugfixes and new Features. For details see CHANGELOG.md</PackageReleaseNotes>
1616
<PackageProjectUrl>https://github.com/StefH/System.Linq.Dynamic.Core</PackageProjectUrl>
1717
<PackageLicenseUrl>https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/licence.txt</PackageLicenseUrl>
1818
<RepositoryType>git</RepositoryType>

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [CanBeNull] P
500500
Check.NotEmpty(keySelector, nameof(keySelector));
501501
Check.NotEmpty(resultSelector, nameof(resultSelector));
502502

503-
bool createParameterCtor = source.IsLinqToObjects();
503+
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
504504
LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args);
505505
LambdaExpression elementLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, resultSelector, args);
506506

@@ -570,7 +570,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [CanBeNull] P
570570
Check.NotNull(source, nameof(source));
571571
Check.NotEmpty(keySelector, nameof(keySelector));
572572

573-
bool createParameterCtor = source.IsLinqToObjects();
573+
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
574574
LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args);
575575

576576
var optimized = OptimizeExpression(Expression.Call(
@@ -586,7 +586,6 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str
586586
{
587587
return GroupBy(source, (ParsingConfig)null, keySelector, args);
588588
}
589-
590589
#endregion GroupBy
591590

592591
#region GroupByMany
@@ -897,7 +896,7 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source)
897896
#if NET35
898897
public static object LastOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
899898
#else
900-
public static dynamic LastOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
899+
public static dynamic LastOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
901900
#endif
902901
{
903902
Check.NotNull(source, nameof(source));
@@ -1580,7 +1579,7 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source)
15801579
#if NET35
15811580
public static object SingleOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
15821581
#else
1583-
public static dynamic SingleOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
1582+
public static dynamic SingleOrDefault([NotNull] this IQueryable source, [CanBeNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
15841583
#endif
15851584
{
15861585
Check.NotNull(source, nameof(source));

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider
4444
/// <summary>
4545
/// Gets or sets a value indicating whether to use dynamic object class for anonymous types.
4646
/// </summary>
47-
/// <value>
48-
/// <c>true</c> if wether to use dynamic object class for anonymous types; otherwise, <c>false</c>.
49-
/// </value>
5047
public bool UseDynamicObjectClassForAnonymousTypes { get; set; }
48+
49+
/// <summary>
50+
/// Gets or sets a value indicating whether the EntityFramwwork version supports evaluating GroupBy at database level.
51+
/// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation
52+
/// </summary>
53+
public bool EvaluateGroupByAtDatabase { get; set; }
5154
}
5255
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
<AssemblyTitle>System.Linq.Dynamic.Core</AssemblyTitle>
55
<VersionPrefix>1.0.8.11</VersionPrefix>
66
<Authors>Microsoft;Scott Guthrie;King Wilder;Nathan Arnott;Stef Heyenrath</Authors>
7-
<TargetFrameworks>net35;net40;net45;net46;uap10.0;netstandard1.3;netstandard2.0</TargetFrameworks>
7+
<TargetFrameworks>net35;net40;net45;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
88
<GenerateDocumentationFile>true</GenerateDocumentationFile>
99
<AssemblyName>System.Linq.Dynamic.Core</AssemblyName>
1010
<AssemblyOriginatorKeyFile>System.Linq.Dynamic.Core.snk</AssemblyOriginatorKeyFile>
1111
<SignAssembly>true</SignAssembly>
1212
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
1313
<PackageTags>system;linq;dynamic;core;dotnet;NETCoreApp;NETStandard</PackageTags>
14-
<PackageReleaseNotes>Bugfixes and new Features. For details see the release notes.</PackageReleaseNotes>
14+
<PackageReleaseNotes>Bugfixes and new Features. For details see CHANGELOG.md</PackageReleaseNotes>
1515
<PackageProjectUrl>https://github.com/StefH/System.Linq.Dynamic.Core</PackageProjectUrl>
1616
<PackageLicenseUrl>https://github.com/StefH/System.Linq.Dynamic.Core/blob/master/licence.txt</PackageLicenseUrl>
1717
<RepositoryType>git</RepositoryType>

0 commit comments

Comments
 (0)