diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln index ebf06692..8d2e915a 100644 --- a/System.Linq.Dynamic.Core.sln +++ b/System.Linq.Dynamic.Core.sln @@ -90,6 +90,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docfx", "docfx", "{012536E6 docfx\toc.yml = docfx\toc.yml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lab", "lab", "{E97833C1-77B6-44E2-8793-C1F952CA936F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z.Dynamic.Core.Lab", "Z.Dynamic.Core.Lab\Z.Dynamic.Core.Lab.csproj", "{CDD8D5BF-A212-43DD-B043-4B7242C553E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -504,6 +508,22 @@ Global {CD80A3AC-B0E1-45ED-BE07-DE6A0F1D4CD8}.Release|x64.Build.0 = Release|Any CPU {CD80A3AC-B0E1-45ED-BE07-DE6A0F1D4CD8}.Release|x86.ActiveCfg = Release|Any CPU {CD80A3AC-B0E1-45ED-BE07-DE6A0F1D4CD8}.Release|x86.Build.0 = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|ARM.Build.0 = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|x64.ActiveCfg = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|x64.Build.0 = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|x86.ActiveCfg = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Debug|x86.Build.0 = Debug|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|Any CPU.Build.0 = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|ARM.ActiveCfg = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|ARM.Build.0 = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|x64.ActiveCfg = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|x64.Build.0 = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|x86.ActiveCfg = Release|Any CPU + {CDD8D5BF-A212-43DD-B043-4B7242C553E0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -534,6 +554,7 @@ Global {D160E2CF-A7E1-4DDE-9AB8-8CFB0087DCEB} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} {0034821E-740D-4553-821B-14CE9213C43C} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62} {CD80A3AC-B0E1-45ED-BE07-DE6A0F1D4CD8} = {122BC4FA-7563-4E35-9D17-077F16F1629F} + {CDD8D5BF-A212-43DD-B043-4B7242C553E0} = {E97833C1-77B6-44E2-8793-C1F952CA936F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20} diff --git a/Z.Dynamic.Core.Lab/Program.cs b/Z.Dynamic.Core.Lab/Program.cs new file mode 100644 index 00000000..457b1b38 --- /dev/null +++ b/Z.Dynamic.Core.Lab/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace Z.Dynamic.Core.Lab +{ + class Program + { + static void Main(string[] args) + { + Request_OrderBy_StringComparer.Execute(); + } + } +} diff --git a/Z.Dynamic.Core.Lab/Request_OrderBy_StringComparer.cs b/Z.Dynamic.Core.Lab/Request_OrderBy_StringComparer.cs new file mode 100644 index 00000000..fe4d7194 --- /dev/null +++ b/Z.Dynamic.Core.Lab/Request_OrderBy_StringComparer.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Text; + +namespace Z.Dynamic.Core.Lab +{ + class Request_OrderBy_StringComparer + { + public class Customer + { + public string City { get; set; } + public List Orders { get; set; } + public string CompanyName { get; set; } + public string Phone { get; set; } + } + public class Order + { + } + + public static void Execute() + { + List customers = new List() { new Customer() { CompanyName = "Ååå"} , + new Customer() { CompanyName = "Bbb" } , + new Customer() { CompanyName = "Ååå" } , + new Customer() { CompanyName = "Bbb" } , + new Customer() { CompanyName = "Aaa" }, + new Customer() { CompanyName = "Aaa" }, +}; + + CultureInfo culture = new CultureInfo("nb-NO"); + var test1 = customers.AsQueryable().OrderBy(x => x.CompanyName, StringComparer.Create(culture, true)).ToList(); + var test2 = customers.AsQueryable().OrderBy(x => x.CompanyName).ToList(); + var test3 = customers.AsQueryable() + .OrderBy("City").ThenBy("CompanyName", StringComparer.Create(culture, true)).ToDynamicList(); + var test4 = customers.AsQueryable() + .OrderBy("CompanyName", StringComparer.Create(culture, true)).ToDynamicList(); + } + } +} diff --git a/Z.Dynamic.Core.Lab/Template_Simple.cs b/Z.Dynamic.Core.Lab/Template_Simple.cs new file mode 100644 index 00000000..989a0418 --- /dev/null +++ b/Z.Dynamic.Core.Lab/Template_Simple.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Linq.Dynamic.Core; + +namespace Z.Dynamic.Core.Lab +{ + public class Template_Simple + { + public class Customer + { + public string City { get; set; } + public List Orders { get; set; } + public string CompanyName { get; set; } + public string Phone { get; set; } + } + public class Order + { + } + + public static void Execute() + { + List customers = new List() {new Customer() {City = "ZZZ", CompanyName = "ZZZ", Orders = new List() {new Order()}, Phone = "555 5555"}}; + + var query = customers.AsQueryable() + .Where("City == @0 and Orders.Count >= @1", "ZZZ", 1) + .OrderBy("CompanyName") + .Select("new(CompanyName as Name, Phone)").ToDynamicList(); + } + } +} diff --git a/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj b/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj new file mode 100644 index 00000000..1c541a91 --- /dev/null +++ b/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index 4870746c..03904924 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -1273,6 +1273,35 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya return OrderBy(source, ParsingConfig.Default, ordering, args); } + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// The type of the elements of source. + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// The comparer to use to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + { + return (IOrderedQueryable)InternalOrderBy((IQueryable)source, config, ordering, comparer, args); + } + + /// + /// Sorts the elements of a sequence in ascending or descending order according to a key. + /// + /// The type of the elements of source. + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// The comparer to use to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + { + return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); + } + /// /// Sorts the elements of a sequence in ascending or descending order according to a key. /// @@ -1289,6 +1318,11 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// /// public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + { + return InternalOrderBy(source, config, ordering, null, args); + } + + internal static IOrderedQueryable InternalOrderBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) { Check.NotNull(source, nameof(source)); Check.NotNull(config, nameof(config)); @@ -1302,10 +1336,22 @@ public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNu foreach (DynamicOrdering dynamicOrdering in dynamicOrderings) { - queryExpr = Expression.Call( - typeof(Queryable), dynamicOrdering.MethodName, - new[] { source.ElementType, dynamicOrdering.Selector.Type }, - queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters))); + if (comparer == null) + { + queryExpr = Expression.Call( + typeof(Queryable), dynamicOrdering.MethodName, + new[] { source.ElementType, dynamicOrdering.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters))); + } + else + { + var comparerGenericType = typeof(IComparer<>).MakeGenericType(dynamicOrdering.Selector.Type); + queryExpr = Expression.Call( + typeof(Queryable), dynamicOrdering.MethodName, + new[] { source.ElementType, dynamicOrdering.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters)), + Expression.Constant(comparer, comparerGenericType)); + } } var optimized = OptimizeExpression(queryExpr); @@ -2176,6 +2222,35 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered { return ThenBy(source, ParsingConfig.Default, ordering, args); } + + /// + /// Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. + /// + /// The type of the elements of source. + /// A sequence of values to order. + /// The . + /// An expression string to indicate values to order by. + /// The comparer to use to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + { + return (IOrderedQueryable)InternalThenBy((IOrderedQueryable)source, config, ordering, comparer, args); + } + + /// + /// Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. + /// + /// The type of the elements of source. + /// A sequence of values to order. + /// An expression string to indicate values to order by. + /// The comparer to use to order by. + /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. + /// A whose elements are sorted according to the specified . + public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + { + return ThenBy(source, ParsingConfig.Default, ordering, comparer, args); + } /// /// Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. /// @@ -2193,6 +2268,11 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// /// public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + { + return InternalThenBy(source, config, ordering, null, args); + } + + internal static IOrderedQueryable InternalThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) { Check.NotNull(source, nameof(source)); Check.NotNull(config, nameof(config)); @@ -2206,10 +2286,22 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, foreach (DynamicOrdering dynamicOrdering in dynamicOrderings) { - queryExpr = Expression.Call( - typeof(Queryable), dynamicOrdering.MethodName, - new[] { source.ElementType, dynamicOrdering.Selector.Type }, - queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters))); + if (comparer == null) + { + queryExpr = Expression.Call( + typeof(Queryable), dynamicOrdering.MethodName, + new[] { source.ElementType, dynamicOrdering.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters))); + } + else + { + var comparerGenericType = typeof(IComparer<>).MakeGenericType(dynamicOrdering.Selector.Type); + queryExpr = Expression.Call( + typeof(Queryable), dynamicOrdering.MethodName, + new[] { source.ElementType, dynamicOrdering.Selector.Type }, + queryExpr, Expression.Quote(Expression.Lambda(dynamicOrdering.Selector, parameters)), + Expression.Constant(comparer, comparerGenericType)); + } } var optimized = OptimizeExpression(queryExpr);