Skip to content

Commit 27df473

Browse files
committed
support more dynamic operations
1 parent 9f9ec17 commit 27df473

File tree

1 file changed

+120
-118
lines changed

1 file changed

+120
-118
lines changed

src/EfCore/DKNet.EfCore.Specifications/Dynamics/DynamicPredicateExtensions.cs

Lines changed: 120 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,20 @@
1212
namespace LinqKit;
1313

1414
/// <summary>
15-
/// Extension methods for combining dynamic LINQ expressions with LinqKit's ExpressionStarter.
16-
/// Provides fluent API for building complex predicates using string-based dynamic expressions.
15+
/// Provides dynamic predicate helpers for LinqKit predicates.
1716
/// </summary>
1817
public static class DynamicPredicateExtensions
1918
{
2019
#region Methods
2120

2221
/// <summary>
23-
/// Builds a dynamic predicate expression for the given property, operation, and value using System.Linq.Dynamic.Core.
24-
/// Returns null if the property is not found or the value is invalid for the property type.
22+
/// Builds a dynamic predicate for a property filter.
2523
/// </summary>
26-
/// <typeparam name="T">The entity type</typeparam>
27-
/// <param name="propertyName">Property name or path (dot notation supported)</param>
28-
/// <param name="operation">Operation to perform</param>
29-
/// <param name="value">Value to compare</param>
30-
/// <returns>Expression or null if not valid</returns>
24+
/// <typeparam name="T">Entity type.</typeparam>
25+
/// <param name="propertyName">Property name or dotted path.</param>
26+
/// <param name="operation">Filter operation.</param>
27+
/// <param name="value">Filter value.</param>
28+
/// <returns>A parsed predicate, or <see langword="null"/> when invalid.</returns>
3129
private static Expression<Func<T, bool>>? BuildDynamicExpression<T>(string propertyName,
3230
Ops operation, object? value)
3331
{
@@ -62,119 +60,123 @@ public static class DynamicPredicateExtensions
6260
return lambda;
6361
}
6462

65-
/// <summary>
66-
/// Combines the existing predicate with a new dynamic condition using AND logic.
67-
/// If the dynamic expression is null or empty, the original predicate is returned unchanged.
68-
/// Property name/path may be provided in camelCase, snake_case, kebab-case or mixed; each dotted segment is
69-
/// normalized to PascalCase.
70-
/// </summary>
71-
/// <typeparam name="T">The type of the entity being queried</typeparam>
72-
/// <param name="predicate">The existing expression starter to extend</param>
73-
/// <param name="propertyName">
74-
/// The name of the property to filter on. Supports nested properties using dot notation (e.g., "Address.City").
75-
/// </param>
76-
/// <param name="operation">
77-
/// The comparison operation to perform (e.g., Equal, GreaterThan, Contains).
78-
/// </param>
79-
/// <param name="value">
80-
/// The value to compare against. The type should match the property type.
81-
/// </param>
82-
/// <returns>
83-
/// The extended <see cref="ExpressionStarter{T}" /> with the AND condition applied, or the original predicate if the
84-
/// dynamic expression is null
85-
/// </returns>
86-
public static Expression<Func<T, bool>> DynamicAnd<T>(this ExpressionStarter<T> predicate,
87-
string propertyName, Ops operation, object? value)
88-
{
89-
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
90-
return dynamicExpression == null ? predicate : predicate.And(dynamicExpression);
91-
}
92-
93-
/// <summary>
94-
/// Combines the existing predicate with a new dynamic condition using AND logic.
95-
/// If the dynamic expression is null or empty, the original predicate is returned unchanged.
96-
/// Property name/path may be provided in camelCase, snake_case, kebab-case or mixed; each dotted segment is
97-
/// normalized to PascalCase.
98-
/// </summary>
99-
/// <typeparam name="T">The type of the entity being queried</typeparam>
100-
/// <param name="predicate">The existing expression starter to extend</param>
101-
/// <param name="propertyName">
102-
/// The name of the property to filter on. Supports nested properties using dot notation (e.g., "Address.City").
103-
/// </param>
104-
/// <param name="operation">
105-
/// The comparison operation to perform (e.g., Equal, GreaterThan, Contains).
106-
/// </param>
107-
/// <param name="value">
108-
/// The value to compare against. The type should match the property type.
109-
/// </param>
110-
/// <returns>
111-
/// The extended <see cref="ExpressionStarter{T}" /> with the AND condition applied, or the original predicate if the
112-
/// dynamic expression is null
113-
/// </returns>
114-
public static Expression<Func<T, bool>> DynamicAnd<T>(this Expression<Func<T, bool>> predicate,
115-
string propertyName, Ops operation, object? value)
116-
{
117-
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
118-
return dynamicExpression == null ? predicate : predicate.And(dynamicExpression);
119-
}
63+
#endregion
12064

121-
/// <summary>
122-
/// Combines the existing predicate with a new dynamic condition using OR logic.
123-
/// If the dynamic expression is null or empty, the original predicate is returned unchanged.
124-
/// Property name/path may be provided in camelCase, snake_case, kebab-case or mixed; each dotted segment is
125-
/// normalized to PascalCase.
126-
/// </summary>
127-
/// <typeparam name="T">The type of the entity being queried</typeparam>
128-
/// <param name="predicate">The existing expression starter to extend</param>
129-
/// <param name="propertyName">
130-
/// The name of the property to filter on. Supports nested properties using dot notation (e.g., "Address.City").
131-
/// </param>
132-
/// <param name="operation">
133-
/// The comparison operation to perform (e.g., Equal, GreaterThan, Contains).
134-
/// </param>
135-
/// <param name="value">
136-
/// The value to compare against. The type should match the property type.
137-
/// </param>
138-
/// <returns>
139-
/// The extended <see cref="ExpressionStarter{T}" /> with the OR condition applied, or the original predicate if the
140-
/// dynamic expression is null
141-
/// </returns>
142-
public static Expression<Func<T, bool>> DynamicOr<T>(
143-
this ExpressionStarter<T> predicate,
144-
string propertyName, Ops operation, object? value)
65+
extension<T>(ExpressionStarter<T> predicate)
14566
{
146-
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
147-
return dynamicExpression == null ? predicate : predicate.Or(dynamicExpression);
67+
/// <summary>
68+
/// Adds a dynamic condition using AND.
69+
/// </summary>
70+
/// <typeparam name="T">Entity type.</typeparam>
71+
/// <param name="propertyName">Property name or dotted path.</param>
72+
/// <param name="operation">Filter operation.</param>
73+
/// <param name="value">Filter value.</param>
74+
/// <returns>The combined predicate.</returns>
75+
public Expression<Func<T, bool>> DynamicAnd(string propertyName, Ops operation, object? value)
76+
{
77+
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
78+
return dynamicExpression == null ? predicate : predicate.And(dynamicExpression);
79+
}
80+
81+
/// <summary>
82+
/// Adds a dynamic condition using OR.
83+
/// </summary>
84+
/// <typeparam name="T">Entity type.</typeparam>
85+
/// <param name="propertyName">Property name or dotted path.</param>
86+
/// <param name="operation">Filter operation.</param>
87+
/// <param name="value">Filter value.</param>
88+
/// <returns>The combined predicate.</returns>
89+
public Expression<Func<T, bool>> DynamicOr(string propertyName, Ops operation, object? value)
90+
{
91+
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
92+
return dynamicExpression == null ? predicate : predicate.Or(dynamicExpression);
93+
}
94+
95+
/// <summary>
96+
/// Parses a dynamic LINQ expression and combines it using AND.
97+
/// </summary>
98+
/// <param name="expression">Dynamic LINQ expression.</param>
99+
/// <param name="values">Expression parameter values.</param>
100+
/// <returns>The combined predicate.</returns>
101+
public ExpressionStarter<T> DynamicAnd(string expression,
102+
params object?[] values)
103+
{
104+
var dynamicExpr =
105+
DynamicExpressionParser.ParseLambda<T, bool>(ParsingConfig.Default, false, expression, values);
106+
return predicate.And(dynamicExpr);
107+
}
108+
109+
/// <summary>
110+
/// Parses a dynamic LINQ expression and combines it using OR.
111+
/// </summary>
112+
/// <param name="expression">Dynamic LINQ expression.</param>
113+
/// <param name="values">Expression parameter values.</param>
114+
/// <returns>The combined predicate.</returns>
115+
public ExpressionStarter<T> DynamicOr(string expression,
116+
params object?[] values)
117+
{
118+
var dynamicExpr =
119+
DynamicExpressionParser.ParseLambda<T, bool>(ParsingConfig.Default, false, expression, values);
120+
return predicate.Or(dynamicExpr);
121+
}
148122
}
149123

150-
/// <summary>
151-
/// Combines the existing predicate with a new dynamic condition using OR logic.
152-
/// If the dynamic expression is null or empty, the original predicate is returned unchanged.
153-
/// Property name/path may be provided in camelCase, snake_case, kebab-case or mixed; each dotted segment is
154-
/// normalized to PascalCase.
155-
/// </summary>
156-
/// <typeparam name="T">The type of the entity being queried</typeparam>
157-
/// <param name="predicate">The existing expression starter to extend</param>
158-
/// <param name="propertyName">
159-
/// The name of the property to filter on. Supports nested properties using dot notation (e.g., "Address.City").
160-
/// </param>
161-
/// <param name="operation">
162-
/// The comparison operation to perform (e.g., Equal, GreaterThan, Contains).
163-
/// </param>
164-
/// <param name="value">
165-
/// The value to compare against. The type should match the property type.
166-
/// </param>
167-
/// <returns>
168-
/// The extended <see cref="ExpressionStarter{T}" /> with the OR condition applied, or the original predicate if the
169-
/// dynamic expression is null
170-
/// </returns>
171-
public static Expression<Func<T, bool>> DynamicOr<T>(
172-
this Expression<Func<T, bool>> predicate,
173-
string propertyName, Ops operation, object? value)
124+
extension<T>(Expression<Func<T, bool>> predicate)
174125
{
175-
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
176-
return dynamicExpression == null ? predicate : predicate.Or(dynamicExpression);
126+
/// <summary>
127+
/// Adds a dynamic condition using AND.
128+
/// </summary>
129+
/// <typeparam name="T">Entity type.</typeparam>
130+
/// <param name="propertyName">Property name or dotted path.</param>
131+
/// <param name="operation">Filter operation.</param>
132+
/// <param name="value">Filter value.</param>
133+
/// <returns>The combined predicate.</returns>
134+
public Expression<Func<T, bool>> DynamicAnd(string propertyName, Ops operation, object? value)
135+
{
136+
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
137+
return dynamicExpression == null ? predicate : predicate.And(dynamicExpression);
138+
}
139+
140+
/// <summary>
141+
/// Adds a dynamic condition using OR.
142+
/// </summary>
143+
/// <typeparam name="T">Entity type.</typeparam>
144+
/// <param name="propertyName">Property name or dotted path.</param>
145+
/// <param name="operation">Filter operation.</param>
146+
/// <param name="value">Filter value.</param>
147+
/// <returns>The combined predicate.</returns>
148+
public Expression<Func<T, bool>> DynamicOr(string propertyName, Ops operation, object? value)
149+
{
150+
var dynamicExpression = BuildDynamicExpression<T>(propertyName, operation, value);
151+
return dynamicExpression == null ? predicate : predicate.Or(dynamicExpression);
152+
}
153+
154+
/// <summary>
155+
/// Parses a dynamic LINQ expression and combines it using AND.
156+
/// </summary>
157+
/// <param name="expression">Dynamic LINQ expression.</param>
158+
/// <param name="values">Expression parameter values.</param>
159+
/// <returns>The combined predicate.</returns>
160+
public ExpressionStarter<T> DynamicAnd(string expression,
161+
params object?[] values)
162+
{
163+
var dynamicExpr =
164+
DynamicExpressionParser.ParseLambda<T, bool>(ParsingConfig.Default, false, expression, values);
165+
return predicate.And(dynamicExpr);
166+
}
167+
168+
/// <summary>
169+
/// Parses a dynamic LINQ expression and combines it using OR.
170+
/// </summary>
171+
/// <param name="expression">Dynamic LINQ expression.</param>
172+
/// <param name="values">Expression parameter values.</param>
173+
/// <returns>The combined predicate.</returns>
174+
public ExpressionStarter<T> DynamicOr(string expression,
175+
params object?[] values)
176+
{
177+
var dynamicExpr =
178+
DynamicExpressionParser.ParseLambda<T, bool>(ParsingConfig.Default, false, expression, values);
179+
return predicate.Or(dynamicExpr);
180+
}
177181
}
178-
179-
#endregion
180182
}

0 commit comments

Comments
 (0)