Skip to content

Commit c814eb2

Browse files
authored
GenerateConditional will cast to nullable valuetype if needed (#222)
* GenerateConditional will cast to nullable valuetype if needed * codefactor
1 parent f98cba5 commit c814eb2

File tree

6 files changed

+273
-177
lines changed

6 files changed

+273
-177
lines changed

System.Linq.Dynamic.Core.sln

-4
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,13 @@ Global
181181
{BF97CB1B-5043-4256-8F42-CF3A4F3863BE}.Release|x86.ActiveCfg = Release|Any CPU
182182
{BF97CB1B-5043-4256-8F42-CF3A4F3863BE}.Release|x86.Build.0 = Release|Any CPU
183183
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
184-
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
185184
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|ARM.ActiveCfg = Debug|Any CPU
186185
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|ARM.Build.0 = Debug|Any CPU
187186
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|x64.ActiveCfg = Debug|Any CPU
188187
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|x64.Build.0 = Debug|Any CPU
189188
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|x86.ActiveCfg = Debug|Any CPU
190189
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Debug|x86.Build.0 = Debug|Any CPU
191190
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
192-
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Release|Any CPU.Build.0 = Release|Any CPU
193191
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Release|ARM.ActiveCfg = Release|Any CPU
194192
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Release|ARM.Build.0 = Release|Any CPU
195193
{27E54CD4-1D80-4797-88DC-1C535C1E9B4A}.Release|x64.ActiveCfg = Release|Any CPU
@@ -377,15 +375,13 @@ Global
377375
{926D446C-8358-465A-AFAC-2F9078C22262}.Release|x86.Build.0 = Release|x86
378376
{926D446C-8358-465A-AFAC-2F9078C22262}.Release|x86.Deploy.0 = Release|x86
379377
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
380-
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
381378
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|ARM.ActiveCfg = Debug|Any CPU
382379
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|ARM.Build.0 = Debug|Any CPU
383380
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|x64.ActiveCfg = Debug|Any CPU
384381
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|x64.Build.0 = Debug|Any CPU
385382
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|x86.ActiveCfg = Debug|Any CPU
386383
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Debug|x86.Build.0 = Debug|Any CPU
387384
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
388-
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|Any CPU.Build.0 = Release|Any CPU
389385
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|ARM.ActiveCfg = Release|Any CPU
390386
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|ARM.Build.0 = Release|Any CPU
391387
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|x64.ActiveCfg = Release|Any CPU

src-console/ConsoleAppEF2.1.1_InMemory/Program.cs

+18-5
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ public class NestedDto
1717
{
1818
public string Name { get; set; }
1919

20-
public class NestedDto2
21-
{
22-
public string Name2 { get; set; }
23-
}
20+
public NestedDto2 NestedDto2 { get; set; }
21+
22+
23+
}
24+
25+
public class NestedDto2
26+
{
27+
public string Name2 { get; set; }
28+
29+
public int Id { get; set; }
2430
}
2531

2632
class NetCore21CustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
@@ -166,6 +172,13 @@ private static TResult Execute<TResult>(MethodInfo operatorMethodInfo, IQueryabl
166172

167173
static void Main(string[] args)
168174
{
175+
var q = new[] { new NestedDto(), new NestedDto { NestedDto2 = new NestedDto2 { Id = 42 } } }.AsQueryable();
176+
var r1 = q.Select("it != null && it.NestedDto2 != null ? it.NestedDto2.Id : null");
177+
var list1 = r1.ToDynamicList<int?>();
178+
179+
var r2 = q.Select("it != null && it.NestedDto2 != null ? it.NestedDto2 : null");
180+
var list2 = r2.ToDynamicList<NestedDto2>();
181+
169182
var config = new ParsingConfig
170183
{
171184
AllowNewToEvaluateAnyType = true,
@@ -211,7 +224,7 @@ static void Main(string[] args)
211224
var any2 = anyTest.Where("values.Contains(1)");
212225
Console.WriteLine("any2 {0}", JsonConvert.SerializeObject(any2, Formatting.Indented));
213226

214-
227+
215228

216229
var dateLastModified = new DateTime(2018, 1, 15);
217230

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

+25-1
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,31 @@ Expression GenerateConditional(Expression test, Expression expr1, Expression exp
10681068

10691069
if (expr1.Type != expr2.Type)
10701070
{
1071+
if ((expr1 == Constants.NullLiteral && expr2.Type.GetTypeInfo().IsValueType) || (expr2 == Constants.NullLiteral && expr1.Type.GetTypeInfo().IsValueType))
1072+
{
1073+
// If expr1 is a null constant and expr2 is a IsValueType:
1074+
// - create nullable constant from expr1 with type from expr2
1075+
// - convert expr2 to nullable
1076+
if (expr1 == Constants.NullLiteral && expr2.Type.GetTypeInfo().IsValueType)
1077+
{
1078+
Type nullableType = typeof(Nullable<>).MakeGenericType(expr2.Type);
1079+
expr1 = Expression.Constant(null, nullableType);
1080+
expr2 = Expression.Convert(expr2, nullableType);
1081+
}
1082+
1083+
// If expr2 is a null constant and expr1 is a IsValueType:
1084+
// - create nullable constant from expr2 with type from expr1
1085+
// - convert expr1 to nullable
1086+
if (expr2 == Constants.NullLiteral && expr1.Type.GetTypeInfo().IsValueType)
1087+
{
1088+
Type nullableType = typeof(Nullable<>).MakeGenericType(expr1.Type);
1089+
expr2 = Expression.Constant(null, nullableType);
1090+
expr1 = Expression.Convert(expr1, nullableType);
1091+
}
1092+
1093+
return Expression.Condition(test, expr1, expr2);
1094+
}
1095+
10711096
Expression expr1As2 = expr2 != Constants.NullLiteral ? _parsingConfig.ExpressionPromoter.Promote(expr1, expr2.Type, true, false) : null;
10721097
Expression expr2As1 = expr1 != Constants.NullLiteral ? _parsingConfig.ExpressionPromoter.Promote(expr2, expr1.Type, true, false) : null;
10731098
if (expr1As2 != null && expr2As1 == null)
@@ -1869,5 +1894,4 @@ static Exception ParseError(int pos, string format, params object[] args)
18691894
return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos);
18701895
}
18711896
}
1872-
18731897
}

test/System.Linq.Dynamic.Core.Tests/EntitiesTests.Cast.cs

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Xunit;
1+
using NFluent;
2+
using Xunit;
23

34
namespace System.Linq.Dynamic.Core.Tests
45
{
@@ -19,6 +20,20 @@ public void Cast_To_nullableint()
1920
Assert.Equal(expectedResult, result);
2021
}
2122

23+
[Fact]
24+
public void Cast_To_nullableint_Automatic()
25+
{
26+
// Arrange
27+
PopulateTestData(5, 0);
28+
29+
// Act
30+
var expectedResult = _context.Blogs.Select(b => b.BlogId == 2 ? (int?)b.BlogId : null).ToList();
31+
var result = _context.Blogs.AsQueryable().Select("BlogId == 2 ? BlogId : null").ToDynamicList<int?>();
32+
33+
// Assert
34+
Check.That(result).ContainsExactly(expectedResult);
35+
}
36+
2237
[Fact]
2338
public void Cast_To_nullablelong()
2439
{
@@ -48,4 +63,4 @@ public void Cast_To_newnullableint()
4863
Assert.Equal(expectedResult, result);
4964
}
5065
}
51-
}
66+
}

0 commit comments

Comments
 (0)