Skip to content

Commit 02910bd

Browse files
Merge pull request #399 from ascott18/UseParameterizedNamesInDynamicQuery
Use parameterized names in dynamic query
2 parents 2821de8 + 069311c commit 02910bd

File tree

7 files changed

+210
-24
lines changed

7 files changed

+210
-24
lines changed

src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs

+80
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,26 @@ public void Wrap(ref Expression expression)
1616
{
1717
expression = WrappedConstant((bool)constantExpression.Value);
1818
}
19+
else if (constantExpression.Type == typeof(bool?))
20+
{
21+
expression = WrappedConstant((bool?)constantExpression.Value);
22+
}
1923
else if (constantExpression.Type == typeof(char))
2024
{
2125
expression = WrappedConstant((char)constantExpression.Value);
2226
}
27+
else if (constantExpression.Type == typeof(char?))
28+
{
29+
expression = WrappedConstant((char?)constantExpression.Value);
30+
}
2331
else if (constantExpression.Type == typeof(byte))
2432
{
2533
expression = WrappedConstant((byte)constantExpression.Value);
2634
}
35+
else if (constantExpression.Type == typeof(byte?))
36+
{
37+
expression = WrappedConstant((byte?)constantExpression.Value);
38+
}
2739
else if (constantExpression.Type == typeof(sbyte))
2840
{
2941
expression = WrappedConstant((sbyte)constantExpression.Value);
@@ -36,54 +48,106 @@ public void Wrap(ref Expression expression)
3648
{
3749
expression = WrappedConstant((float)constantExpression.Value);
3850
}
51+
else if (constantExpression.Type == typeof(float?))
52+
{
53+
expression = WrappedConstant((float?)constantExpression.Value);
54+
}
3955
else if (constantExpression.Type == typeof(decimal))
4056
{
4157
expression = WrappedConstant((decimal)constantExpression.Value);
4258
}
59+
else if (constantExpression.Type == typeof(decimal?))
60+
{
61+
expression = WrappedConstant((decimal?)constantExpression.Value);
62+
}
4363
else if (constantExpression.Type == typeof(double))
4464
{
4565
expression = WrappedConstant((double)constantExpression.Value);
4666
}
67+
else if (constantExpression.Type == typeof(double?))
68+
{
69+
expression = WrappedConstant((double?)constantExpression.Value);
70+
}
4771
else if (constantExpression.Type == typeof(long))
4872
{
4973
expression = WrappedConstant((long)constantExpression.Value);
5074
}
75+
else if (constantExpression.Type == typeof(long?))
76+
{
77+
expression = WrappedConstant((long?)constantExpression.Value);
78+
}
5179
else if (constantExpression.Type == typeof(ulong))
5280
{
5381
expression = WrappedConstant((ulong)constantExpression.Value);
5482
}
83+
else if (constantExpression.Type == typeof(ulong?))
84+
{
85+
expression = WrappedConstant((ulong?)constantExpression.Value);
86+
}
5587
else if (constantExpression.Type == typeof(int))
5688
{
5789
expression = WrappedConstant((int)constantExpression.Value);
5890
}
91+
else if (constantExpression.Type == typeof(int?))
92+
{
93+
expression = WrappedConstant((int?)constantExpression.Value);
94+
}
5995
else if (constantExpression.Type == typeof(uint))
6096
{
6197
expression = WrappedConstant((uint)constantExpression.Value);
6298
}
99+
else if (constantExpression.Type == typeof(uint?))
100+
{
101+
expression = WrappedConstant((uint?)constantExpression.Value);
102+
}
63103
else if (constantExpression.Type == typeof(short))
64104
{
65105
expression = WrappedConstant((short)constantExpression.Value);
66106
}
107+
else if (constantExpression.Type == typeof(short?))
108+
{
109+
expression = WrappedConstant((short?)constantExpression.Value);
110+
}
67111
else if (constantExpression.Type == typeof(ushort))
68112
{
69113
expression = WrappedConstant((ushort)constantExpression.Value);
70114
}
115+
else if (constantExpression.Type == typeof(ushort?))
116+
{
117+
expression = WrappedConstant((ushort?)constantExpression.Value);
118+
}
71119
else if (constantExpression.Type == typeof(Guid))
72120
{
73121
expression = WrappedConstant((Guid)constantExpression.Value);
74122
}
123+
else if (constantExpression.Type == typeof(Guid?))
124+
{
125+
expression = WrappedConstant((Guid?)constantExpression.Value);
126+
}
75127
else if (constantExpression.Type == typeof(DateTime))
76128
{
77129
expression = WrappedConstant((DateTime)constantExpression.Value);
78130
}
131+
else if (constantExpression.Type == typeof(DateTime?))
132+
{
133+
expression = WrappedConstant((DateTime?)constantExpression.Value);
134+
}
79135
else if (constantExpression.Type == typeof(DateTimeOffset))
80136
{
81137
expression = WrappedConstant((DateTimeOffset)constantExpression.Value);
82138
}
139+
else if (constantExpression.Type == typeof(DateTimeOffset?))
140+
{
141+
expression = WrappedConstant((DateTimeOffset?)constantExpression.Value);
142+
}
83143
else if (constantExpression.Type == typeof(TimeSpan))
84144
{
85145
expression = WrappedConstant((TimeSpan)constantExpression.Value);
86146
}
147+
else if (constantExpression.Type == typeof(TimeSpan?))
148+
{
149+
expression = WrappedConstant((TimeSpan?)constantExpression.Value);
150+
}
87151

88152
return;
89153
}
@@ -94,18 +158,34 @@ public void Wrap(ref Expression expression)
94158
{
95159
expression = WrappedConstant(Expression.Lambda<Func<Guid>>(newExpression).Compile()());
96160
}
161+
else if (newExpression.Type == typeof(Guid?))
162+
{
163+
expression = WrappedConstant(Expression.Lambda<Func<Guid?>>(newExpression).Compile()());
164+
}
97165
else if (newExpression.Type == typeof(DateTime))
98166
{
99167
expression = WrappedConstant(Expression.Lambda<Func<DateTime>>(newExpression).Compile()());
100168
}
169+
else if (newExpression.Type == typeof(DateTime?))
170+
{
171+
expression = WrappedConstant(Expression.Lambda<Func<DateTime?>>(newExpression).Compile()());
172+
}
101173
else if (newExpression.Type == typeof(DateTimeOffset))
102174
{
103175
expression = WrappedConstant(Expression.Lambda<Func<DateTimeOffset>>(newExpression).Compile()());
104176
}
177+
else if (newExpression.Type == typeof(DateTimeOffset?))
178+
{
179+
expression = WrappedConstant(Expression.Lambda<Func<DateTimeOffset?>>(newExpression).Compile()());
180+
}
105181
else if (newExpression.Type == typeof(TimeSpan))
106182
{
107183
expression = WrappedConstant(Expression.Lambda<Func<TimeSpan>>(newExpression).Compile()());
108184
}
185+
else if (newExpression.Type == typeof(TimeSpan?))
186+
{
187+
expression = WrappedConstant(Expression.Lambda<Func<TimeSpan?>>(newExpression).Compile()());
188+
}
109189
}
110190
}
111191

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+2
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,8 @@ Expression ParseUnary()
737737
Expression ParsePrimary()
738738
{
739739
Expression expr = ParsePrimaryStart();
740+
_expressionHelper.WrapConstantExpression(ref expr);
741+
740742
while (true)
741743
{
742744
if (_textParser.CurrentToken.Id == TokenId.Dot)

test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj

+4-1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@
263263
<Compile Include="..\System.Linq.Dynamic.Core.Tests\Helpers\TestEnum.cs">
264264
<Link>Helpers\TestEnum.cs</Link>
265265
</Compile>
266+
<Compile Include="..\System.Linq.Dynamic.Core.Tests\TestHelpers\ExpressionString.cs">
267+
<Link>TestHelpers\ExpressionString.cs</Link>
268+
</Compile>
266269
<Compile Include="..\System.Linq.Dynamic.Core.Tests\OperatorTests.cs">
267270
<Link>OperatorTests.cs</Link>
268271
</Compile>
@@ -380,4 +383,4 @@
380383
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.4.1\build\net20\xunit.runner.visualstudio.props'))" />
381384
</Target>
382385
<Import Project="..\..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
383-
</Project>
386+
</Project>

test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs

+56-22
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using FluentAssertions;
1010
using Xunit;
1111
using User = System.Linq.Dynamic.Core.Tests.Helpers.Models.User;
12+
using System.Linq.Dynamic.Core.Tests.TestHelpers;
1213

1314
namespace System.Linq.Dynamic.Core.Tests
1415
{
@@ -251,6 +252,25 @@ public Type ResolveTypeBySimpleName(string typeName)
251252
}
252253
}
253254

255+
[Fact]
256+
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false()
257+
{
258+
// Assign
259+
var config = new ParsingConfig
260+
{
261+
UseParameterizedNamesInDynamicQuery = false
262+
};
263+
264+
// Act
265+
var expression = DynamicExpressionParser.ParseLambda<string, bool>(config, true, "s => s == \"x\"");
266+
267+
// Assert
268+
dynamic constantExpression = (ConstantExpression)(expression.Body as BinaryExpression).Right;
269+
string value = constantExpression.Value;
270+
271+
Check.That(value).IsEqualTo("x");
272+
}
273+
254274
[Fact]
255275
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true()
256276
{
@@ -261,16 +281,49 @@ public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQu
261281
};
262282

263283
// Act
264-
var expression = DynamicExpressionParser.ParseLambda<string, bool>(config, true, "s => s == \"x\"");
284+
var expression = DynamicExpressionParser.ParseLambda<Person, bool>(config, false, "Id = 42");
285+
string expressionAsString = expression.ToString();
265286

266287
// Assert
288+
Check.That(expressionAsString).IsEqualTo("Param_0 => (Param_0.Id == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value)");
289+
267290
dynamic constantExpression = ((MemberExpression)(expression.Body as BinaryExpression).Right).Expression as ConstantExpression;
268291
dynamic wrappedObj = constantExpression.Value;
269292

270293
var propertyInfo = wrappedObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
271-
string value = propertyInfo.GetValue(wrappedObj) as string;
294+
int value = (int) propertyInfo.GetValue(wrappedObj);
272295

273-
Check.That(value).IsEqualTo("x");
296+
Check.That(value).IsEqualTo(42);
297+
}
298+
299+
[Theory]
300+
[InlineData("NullableIntValue", "42")]
301+
[InlineData("NullableDoubleValue", "42.23")]
302+
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_ForNullableProperty_true(string propName, string valueString)
303+
{
304+
// Assign
305+
var config = new ParsingConfig
306+
{
307+
UseParameterizedNamesInDynamicQuery = true
308+
};
309+
310+
// Act
311+
var expression = DynamicExpressionParser.ParseLambda<SimpleValuesModel, bool>(config, false, $"{propName} = {valueString}");
312+
string expressionAsString = expression.ToString();
313+
314+
// Assert
315+
var queriedProp = typeof(SimpleValuesModel).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public);
316+
var queriedPropType = queriedProp.PropertyType;
317+
var queriedPropUnderlyingType = Nullable.GetUnderlyingType(queriedPropType);
318+
319+
Check.That(expressionAsString).IsEqualTo($"Param_0 => (Param_0.{propName} == {ExpressionString.NullableConversion($"value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[{queriedPropUnderlyingType}]).Value")})");
320+
dynamic constantExpression = ((MemberExpression)(((expression.Body as BinaryExpression).Right as UnaryExpression).Operand)).Expression as ConstantExpression;
321+
object wrapperObj = constantExpression.Value;
322+
323+
var propertyInfo = wrapperObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
324+
object value = propertyInfo.GetValue(wrapperObj);
325+
326+
Check.That(value).IsEqualTo(Convert.ChangeType(valueString, Nullable.GetUnderlyingType(queriedPropType) ?? queriedPropType));
274327
}
275328

276329
[Theory]
@@ -298,25 +351,6 @@ public void DynamicExpressionParser_ParseLambda_WithStructWithEquality(string qu
298351
Check.That(result.ToArray()[0]).Equals(expected[0]);
299352
}
300353

301-
[Fact]
302-
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false()
303-
{
304-
// Assign
305-
var config = new ParsingConfig
306-
{
307-
UseParameterizedNamesInDynamicQuery = false
308-
};
309-
310-
// Act
311-
var expression = DynamicExpressionParser.ParseLambda<string, bool>(config, true, "s => s == \"x\"");
312-
313-
// Assert
314-
dynamic constantExpression = (ConstantExpression)(expression.Body as BinaryExpression).Right;
315-
string value = constantExpression.Value;
316-
317-
Check.That(value).IsEqualTo("x");
318-
}
319-
320354
[Fact]
321355
public void DynamicExpressionParser_ParseLambda_ToList()
322356
{

test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ public class SimpleValuesModel
1010
public decimal DecimalValue { get; set; }
1111

1212
public double DoubleValue { get; set; }
13+
14+
public int? NullableIntValue { get; set; }
15+
16+
public double? NullableDoubleValue { get; set; }
1317
}
14-
}
18+
}

test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionHelperTests.cs

+43
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@ public void ExpressionHelper_WrapConstantExpression_false()
3535
Check.That(expression.ToString()).Equals("\"test\"");
3636
}
3737

38+
[Fact]
39+
public void ExpressionHelper_WrapNullableConstantExpression_false()
40+
{
41+
// Assign
42+
var config = new ParsingConfig
43+
{
44+
UseParameterizedNamesInDynamicQuery = false
45+
};
46+
var expressionHelper = new ExpressionHelper(config);
47+
48+
int? value = 42;
49+
Expression expression = Expression.Constant(value);
50+
51+
// Act
52+
expressionHelper.WrapConstantExpression(ref expression);
53+
54+
// Assert
55+
Check.That(expression).IsInstanceOf<ConstantExpression>();
56+
Check.That(expression.ToString()).Equals("42");
57+
}
58+
3859
[Fact]
3960
public void ExpressionHelper_WrapConstantExpression_true()
4061
{
@@ -57,6 +78,28 @@ public void ExpressionHelper_WrapConstantExpression_true()
5778
Check.That(expression.ToString()).Equals("value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.String]).Value");
5879
}
5980

81+
[Fact]
82+
public void ExpressionHelper_WrapNullableConstantExpression_true()
83+
{
84+
// Assign
85+
var config = new ParsingConfig
86+
{
87+
UseParameterizedNamesInDynamicQuery = true
88+
};
89+
var expressionHelper = new ExpressionHelper(config);
90+
91+
int? value = 42;
92+
Expression expression = Expression.Constant(value);
93+
94+
// Act
95+
expressionHelper.WrapConstantExpression(ref expression);
96+
expressionHelper.WrapConstantExpression(ref expression);
97+
98+
// Assert
99+
Check.That(expression.GetType().FullName).Equals("System.Linq.Expressions.PropertyExpression");
100+
Check.That(expression.ToString()).Equals("value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value");
101+
}
102+
60103
[Fact]
61104
public void ExpressionHelper_OptimizeStringForEqualityIfPossible_Guid()
62105
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace System.Linq.Dynamic.Core.Tests.TestHelpers
8+
{
9+
public static class ExpressionString
10+
{
11+
public static string NullableConversion(string convertedExpr)
12+
{
13+
#if NET452
14+
return $"Convert({convertedExpr})";
15+
#else
16+
return $"Convert({convertedExpr}, Nullable`1)";
17+
#endif
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)