Skip to content

Commit e7f53f4

Browse files
committed
Merge branch 'master' into stef-NET10
2 parents a48941b + 1cc4ea0 commit e7f53f4

30 files changed

+700
-163
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
# v1.6.8 (28 September 2025)
2+
- [#946](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/946) - Fix GroupByMany using composite key and normal key [bug] contributed by [StefH](https://github.com/StefH)
3+
- [#948](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/948) - Add IndexerName attribute to DynamicClass to fix naming issues with Item [bug] contributed by [StefH](https://github.com/StefH)
4+
- [#936](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/936) - AmbiguousMatchException when selecting a property named “Item” using EF Core DbContext [bug]
5+
- [#945](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/945) - ParseException when using composite key for grouping in GroupByMany [bug]
6+
7+
# 1.6.7 (28 July 2025)
8+
- [#938](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/938) - Use TryConvertTypes also for strings [bug] contributed by [StefH](https://github.com/StefH)
9+
10+
# v1.6.6 (11 June 2025)
11+
- [#929](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/929) - Add GroupBy method for Z.DynamicLinq.SystemTextJson and Z.DynamicLinq.NewtonsoftJson contributed by [StefH](https://github.com/StefH)
12+
- [#932](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/932) - Fix "in" for nullable Enums [bug] contributed by [StefH](https://github.com/StefH)
13+
- [#931](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/931) - Syntax IN dont work with nullable Enums [bug]
14+
15+
# v1.6.5 (28 May 2025)
16+
- [#905](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/905) - Fix: Add Fallback in ExpressionPromoter to Handle Cache Cleanup in ConstantExpressionHelper [bug] contributed by [RenanCarlosPereira](https://github.com/RenanCarlosPereira)
17+
- [#904](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/904) - Race Condition in ConstantExpressionHelper Causing Parsing Failures [bug]
18+
119
# v1.6.4 (19 May 2025)
220
- [#915](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/915) - Add support for "not in" and "not_in" [feature] contributed by [StefH](https://github.com/StefH)
321
- [#923](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/923) - Fix MethodFinder TryFindAggregateMethod to support array [bug] contributed by [StefH](https://github.com/StefH)

Generate-ReleaseNotes.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
rem https://github.com/StefH/GitHubReleaseNotes
22

3-
SET version=v1.6.4
3+
SET version=v1.6.8
44

55
GitHubReleaseNotes --output CHANGELOG.md --exclude-labels known_issue out_of_scope not_planned invalid question documentation wontfix environment duplicate --language en --version %version% --token %GH_TOKEN%

README.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
### Library Powered By
2-
3-
This library is powered by [Entity Framework Extensions](https://entityframework-extensions.net/?z=github&y=system.linq.dynamic.core)
4-
5-
<a href="https://entityframework-extensions.net/?z=github&y=system.linq.dynamic.core">
6-
<kbd>
7-
<img src="https://zzzprojects.github.io/images/logo/entityframework-extensions-pub.jpg" alt="Entity Framework Extensions" />
8-
</kbd>
9-
</a>
10-
11-
---
12-
131
# System.Linq.Dynamic.Core
142
This is a **.NET Core / Standard port** of the Microsoft assembly for the .Net 4.0 Dynamic language functionality.
153

4+
---
5+
166
## Overview
177
With this library it's possible to write Dynamic LINQ queries (string based) on an `IQueryable`:
188
``` c#
@@ -32,6 +22,18 @@ db.Customers.WhereInterpolated($"City == {cityName} and Orders.Count >= {c}");
3222

3323
---
3424

25+
## Sponsors
26+
27+
ZZZ Projects owns and maintains **System.Linq.Dynamic.Core** as part of our [mission](https://zzzprojects.com/mission) to add value to the .NET community
28+
29+
Through [Entity Framework Extensions](https://entityframework-extensions.net/?utm_source=zzzprojects&utm_medium=systemlinqdynamiccore) and [Dapper Plus](https://dapper-plus.net/?utm_source=zzzprojects&utm_medium=systemlinqdynamiccore), we actively sponsor and help key open-source libraries grow.
30+
31+
[![Entity Framework Extensions](https://raw.githubusercontent.com/zzzprojects/System.Linq.Dynamic.Core/master/entity-framework-extensions-sponsor.png)](https://entityframework-extensions.net/bulk-insert?utm_source=zzzprojects&utm_medium=systemlinqdynamiccore)
32+
33+
[![Dapper Plus](https://raw.githubusercontent.com/zzzprojects/System.Linq.Dynamic.Core/master/dapper-plus-sponsor.png)](https://dapper-plus.net/bulk-insert?utm_source=zzzprojects&utm_medium=systemlinqdynamiccore)
34+
35+
---
36+
3537
## :exclamation: Breaking changes
3638

3739
### v1.3.0
@@ -82,7 +84,7 @@ Or provide a list of additional types in the [DefaultDynamicLinqCustomTypeProvid
8284
| &nbsp;&nbsp;**Issues** | [![GitHub issues](https://img.shields.io/github/issues/StefH/System.Linq.Dynamic.Core.svg)](https://github.com/StefH/System.Linq.Dynamic.Core/issues) |
8385
| | |
8486
| ***Quality*** | &nbsp; |
85-
| &nbsp;&nbsp;**CI Workflow** | ![CI Workflow](https://github.com/zzzprojects/System.Linq.Dynamic.Core/actions/workflows/ci.yml/badge.svg) |
87+
| &nbsp;&nbsp;**CI Workflow** | [![CI Workflow](https://github.com/zzzprojects/System.Linq.Dynamic.Core/actions/workflows/ci.yml/badge.svg)](https://github.com/zzzprojects/System.Linq.Dynamic.Core/actions/workflows/ci.yml) |
8688
| &nbsp;&nbsp;**SonarCloud** | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=zzzprojects_System.Linq.Dynamic.Core&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=zzzprojects_System.Linq.Dynamic.Core) |
8789
| |
8890
| ***NuGet*** | &nbsp; |

dapper-plus-sponsor.png

10.7 KB
Loading
10.5 KB
Loading

src/System.Linq.Dynamic.Core.NewtonsoftJson/NewtonsoftJsonExtensions.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq.Dynamic.Core.NewtonsoftJson.Config;
33
using System.Linq.Dynamic.Core.NewtonsoftJson.Extensions;
44
using System.Linq.Dynamic.Core.Validation;
5+
using JetBrains.Annotations;
56
using Newtonsoft.Json.Linq;
67

78
namespace System.Linq.Dynamic.Core.NewtonsoftJson;
@@ -303,6 +304,42 @@ public static JToken First(this JArray source, string predicate, params object?[
303304
}
304305
#endregion FirstOrDefault
305306

307+
#region GroupBy
308+
/// <summary>
309+
/// Groups the elements of a sequence according to a specified key string function
310+
/// and creates a result value from each group and its key.
311+
/// </summary>
312+
/// <param name="source">A <see cref="JArray"/> whose elements to group.</param>
313+
/// <param name="keySelector">A string expression to specify the key for each element.</param>
314+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
315+
/// <returns>A <see cref="JArray"/> where each element represents a projection over a group and its key.</returns>
316+
[PublicAPI]
317+
public static JArray GroupBy(this JArray source, string keySelector, params object[]? args)
318+
{
319+
return GroupBy(source, NewtonsoftJsonParsingConfig.Default, keySelector, args);
320+
}
321+
322+
/// <summary>
323+
/// Groups the elements of a sequence according to a specified key string function
324+
/// and creates a result value from each group and its key.
325+
/// </summary>
326+
/// <param name="source">A <see cref="JArray"/> whose elements to group.</param>
327+
/// <param name="config">The <see cref="NewtonsoftJsonParsingConfig"/>.</param>
328+
/// <param name="keySelector">A string expression to specify the key for each element.</param>
329+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
330+
/// <returns>A <see cref="JArray"/> where each element represents a projection over a group and its key.</returns>
331+
[PublicAPI]
332+
public static JArray GroupBy(this JArray source, NewtonsoftJsonParsingConfig config, string keySelector, params object[]? args)
333+
{
334+
Check.NotNull(source);
335+
Check.NotNull(config);
336+
Check.NotNullOrEmpty(keySelector);
337+
338+
var queryable = ToQueryable(source, config);
339+
return ToJArray(() => queryable.GroupBy(config, keySelector, args));
340+
}
341+
#endregion
342+
306343
#region Last
307344
/// <summary>
308345
/// Returns the last element of a sequence that satisfies a specified condition.
@@ -813,7 +850,17 @@ private static JArray ToJArray(Func<IQueryable> func)
813850
var array = new JArray();
814851
foreach (var dynamicElement in func())
815852
{
816-
var element = dynamicElement is DynamicClass dynamicClass ? JObject.FromObject(dynamicClass) : dynamicElement;
853+
var element = dynamicElement switch
854+
{
855+
IGrouping<object, object> grouping => new JObject
856+
{
857+
[nameof(grouping.Key)] = JToken.FromObject(grouping.Key),
858+
["Values"] = ToJArray(grouping.AsQueryable)
859+
},
860+
DynamicClass dynamicClass => JObject.FromObject(dynamicClass),
861+
_ => dynamicElement
862+
};
863+
817864
array.Add(element);
818865
}
819866

src/System.Linq.Dynamic.Core.SystemTextJson/SystemTextJsonExtensions.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq.Dynamic.Core.SystemTextJson.Utils;
66
using System.Linq.Dynamic.Core.Validation;
77
using System.Text.Json;
8+
using JetBrains.Annotations;
89

910
namespace System.Linq.Dynamic.Core.SystemTextJson;
1011

@@ -371,6 +372,42 @@ public static JsonElement First(this JsonDocument source, string predicate, para
371372
}
372373
#endregion FirstOrDefault
373374

375+
#region GroupBy
376+
/// <summary>
377+
/// Groups the elements of a sequence according to a specified key string function
378+
/// and creates a result value from each group and its key.
379+
/// </summary>
380+
/// <param name="source">A <see cref="JsonDocument"/> whose elements to group.</param>
381+
/// <param name="keySelector">A string expression to specify the key for each element.</param>
382+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
383+
/// <returns>A <see cref="JsonDocument"/> where each element represents a projection over a group and its key.</returns>
384+
[PublicAPI]
385+
public static JsonDocument GroupBy(this JsonDocument source, string keySelector, params object[]? args)
386+
{
387+
return GroupBy(source, SystemTextJsonParsingConfig.Default, keySelector, args);
388+
}
389+
390+
/// <summary>
391+
/// Groups the elements of a sequence according to a specified key string function
392+
/// and creates a result value from each group and its key.
393+
/// </summary>
394+
/// <param name="source">A <see cref="JsonDocument"/> whose elements to group.</param>
395+
/// <param name="config">The <see cref="SystemTextJsonParsingConfig"/>.</param>
396+
/// <param name="keySelector">A string expression to specify the key for each element.</param>
397+
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
398+
/// <returns>A <see cref="JsonDocument"/> where each element represents a projection over a group and its key.</returns>
399+
[PublicAPI]
400+
public static JsonDocument GroupBy(this JsonDocument source, SystemTextJsonParsingConfig config, string keySelector, params object[]? args)
401+
{
402+
Check.NotNull(source);
403+
Check.NotNull(config);
404+
Check.NotNullOrEmpty(keySelector);
405+
406+
var queryable = ToQueryable(source, config);
407+
return ToJsonDocumentArray(() => queryable.GroupBy(config, keySelector, args));
408+
}
409+
#endregion
410+
374411
#region Last
375412
/// <summary>
376413
/// Returns the last element of a sequence.
@@ -1037,7 +1074,17 @@ private static JsonDocument ToJsonDocumentArray(Func<IQueryable> func)
10371074
var array = new List<object?>();
10381075
foreach (var dynamicElement in func())
10391076
{
1040-
array.Add(ToJsonElement(dynamicElement));
1077+
var element = dynamicElement switch
1078+
{
1079+
IGrouping<object, object> grouping => ToJsonElement(new
1080+
{
1081+
Key = ToJsonElement(grouping.Key),
1082+
Values = ToJsonDocumentArray(grouping.AsQueryable).RootElement
1083+
}),
1084+
_ => ToJsonElement(dynamicElement)
1085+
};
1086+
1087+
array.Add(element);
10411088
}
10421089

10431090
return JsonDocumentUtils.FromObject(array);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Dynamic;
44
using System.Reflection;
5+
using System.Runtime.CompilerServices;
56

67
namespace System.Linq.Dynamic.Core;
78

@@ -18,6 +19,8 @@ namespace System.Linq.Dynamic.Core;
1819
/// </summary>
1920
public abstract class DynamicClass : DynamicObject
2021
{
22+
internal const string IndexerName = "System_Linq_Dynamic_Core_DynamicClass_Indexer";
23+
2124
private Dictionary<string, object?>? _propertiesDictionary;
2225

2326
private Dictionary<string, object?> Properties
@@ -99,11 +102,12 @@ public void SetDynamicPropertyValue(string propertyName, object value)
99102
/// <value>The <see cref="object"/>.</value>
100103
/// <param name="name">The name.</param>
101104
/// <returns>Value from the property.</returns>
105+
[IndexerName(IndexerName)]
102106
public object? this[string name]
103107
{
104108
get
105109
{
106-
return Properties.TryGetValue(name, out object? result) ? result : null;
110+
return Properties.TryGetValue(name, out var result) ? result : null;
107111
}
108112

109113
set
@@ -153,7 +157,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object? result)
153157
/// </returns>
154158
public override bool TrySetMember(SetMemberBinder binder, object? value)
155159
{
156-
string name = binder.Name;
160+
var name = binder.Name;
157161
if (Properties.ContainsKey(name))
158162
{
159163
Properties[name] = value;

src/System.Linq.Dynamic.Core/DynamicClass.net35.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace System.Linq.Dynamic.Core;
66
/// </summary>
77
public abstract class DynamicClass
88
{
9+
internal const string IndexerName = "System_Linq_Dynamic_Core_DynamicClass_Indexer";
10+
911
/// <summary>
1012
/// Gets the dynamic property by name.
1113
/// </summary>

src/System.Linq.Dynamic.Core/DynamicClass.uap.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#if UAP10_0
22
using System.Collections.Generic;
33
using System.Dynamic;
4+
using System.Runtime.CompilerServices;
45

56
namespace System.Linq.Dynamic.Core;
67

@@ -9,6 +10,8 @@ namespace System.Linq.Dynamic.Core;
910
/// </summary>
1011
public class DynamicClass : DynamicObject
1112
{
13+
internal const string IndexerName = "System_Linq_Dynamic_Core_DynamicClass_Indexer";
14+
1215
private readonly Dictionary<string, object> _properties = new();
1316

1417
/// <summary>
@@ -31,6 +34,7 @@ public DynamicClass(params KeyValuePair<string, object>[] propertylist)
3134
/// </value>
3235
/// <param name="name">The name.</param>
3336
/// <returns>Value from the property.</returns>
37+
[IndexerName(IndexerName)]
3438
public object this[string name]
3539
{
3640
get

0 commit comments

Comments
 (0)