Skip to content

Commit 4d8ce4e

Browse files
gliljasmaca88
andauthored
Fix LINQ projection of nullable enum with list (#2703)
Co-authored-by: maca88 <bostjan.markezic@siol.net>
1 parent 5d374ab commit 4d8ce4e

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

src/NHibernate.Test/Async/Linq/EnumTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
using System;
12+
using System.Collections.Generic;
1213
using System.Linq;
1314
using NHibernate.Cfg.MappingSchema;
1415
using NHibernate.Mapping.ByCode;
@@ -50,9 +51,24 @@ protected override HbmMapping GetMappings()
5051
m.Type(_enumType);
5152
m.Formula($"(case when Enum1 = {_unspecifiedValue} then null else Enum1 end)");
5253
});
54+
rc.Bag(x => x.Children, m =>
55+
{
56+
m.Cascade(Mapping.ByCode.Cascade.All);
57+
m.Inverse(true);
58+
},
59+
a => a.OneToMany()
60+
);
5361
rc.ManyToOne(x => x.Other, m => m.Cascade(Mapping.ByCode.Cascade.All));
5462
});
5563

64+
mapper.Class<EnumEntityChild>(
65+
rc =>
66+
{
67+
rc.Table("EnumEntityChild");
68+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
69+
rc.Property(x => x.Name);
70+
});
71+
5672
return mapper.CompileMappingForAllExplicitlyAddedEntities();
5773
}
5874

@@ -184,5 +200,25 @@ public async Task CanQueryComplexExpressionOnTestEnumAsync()
184200
Assert.That(query.Count, Is.EqualTo(0));
185201
}
186202
}
203+
204+
[Test]
205+
public async Task CanProjectWithListTransformationAsync()
206+
{
207+
using (var session = OpenSession())
208+
using (var trans = session.BeginTransaction())
209+
{
210+
var entities = session.Query<EnumEntity>();
211+
212+
var query = await (entities.Select(user => new
213+
{
214+
user.Name,
215+
simple = user.Enum1,
216+
children = user.Children,
217+
nullableEnum1IsLarge = user.NullableEnum1 == TestEnum.Large
218+
}).ToListAsync());
219+
220+
Assert.That(query.Count, Is.EqualTo(10));
221+
}
222+
}
187223
}
188224
}

src/NHibernate.Test/Linq/EnumTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using NHibernate.Cfg.MappingSchema;
45
using NHibernate.Mapping.ByCode;
@@ -37,9 +38,24 @@ protected override HbmMapping GetMappings()
3738
m.Type(_enumType);
3839
m.Formula($"(case when Enum1 = {_unspecifiedValue} then null else Enum1 end)");
3940
});
41+
rc.Bag(x => x.Children, m =>
42+
{
43+
m.Cascade(Mapping.ByCode.Cascade.All);
44+
m.Inverse(true);
45+
},
46+
a => a.OneToMany()
47+
);
4048
rc.ManyToOne(x => x.Other, m => m.Cascade(Mapping.ByCode.Cascade.All));
4149
});
4250

51+
mapper.Class<EnumEntityChild>(
52+
rc =>
53+
{
54+
rc.Table("EnumEntityChild");
55+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
56+
rc.Property(x => x.Name);
57+
});
58+
4359
return mapper.CompileMappingForAllExplicitlyAddedEntities();
4460
}
4561

@@ -171,6 +187,26 @@ public void CanQueryComplexExpressionOnTestEnum()
171187
Assert.That(query.Count, Is.EqualTo(0));
172188
}
173189
}
190+
191+
[Test]
192+
public void CanProjectWithListTransformation()
193+
{
194+
using (var session = OpenSession())
195+
using (var trans = session.BeginTransaction())
196+
{
197+
var entities = session.Query<EnumEntity>();
198+
199+
var query = entities.Select(user => new
200+
{
201+
user.Name,
202+
simple = user.Enum1,
203+
children = user.Children,
204+
nullableEnum1IsLarge = user.NullableEnum1 == TestEnum.Large
205+
}).ToList();
206+
207+
Assert.That(query.Count, Is.EqualTo(10));
208+
}
209+
}
174210
}
175211

176212
public class EnumEntity
@@ -181,7 +217,17 @@ public class EnumEntity
181217
public virtual TestEnum Enum1 { get; set; }
182218
public virtual TestEnum? NullableEnum1 { get; set; }
183219

220+
public virtual int? NullableInt { get; set; }
221+
184222
public virtual EnumEntity Other { get; set; }
223+
224+
public virtual IList<EnumEntityChild> Children { get; set; } = new List<EnumEntityChild>();
225+
}
226+
227+
public class EnumEntityChild
228+
{
229+
public virtual Guid Id { get; set; }
230+
public virtual string Name { get; set; }
185231
}
186232

187233
public enum TestEnum

src/NHibernate/Linq/NestedSelects/SelectClauseRewriter.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Linq.Expressions;
3+
using NHibernate.Util;
34
using Remotion.Linq.Clauses.Expressions;
45
using Remotion.Linq.Parsing;
56

@@ -41,6 +42,10 @@ public override Expression Visit(Expression expression)
4142
protected override Expression VisitUnary(UnaryExpression node)
4243
{
4344
if (node.NodeType == ExpressionType.Convert &&
45+
// We can skip a convert node only when the underlying types are equal otherwise it
46+
// will throw an exception when trying to convert the value from an object
47+
// (e.g. (int?)(Enum?) input[0] -> (Enum?) cast cannot be skipped)
48+
node.Type.UnwrapIfNullable() == node.Operand.Type.UnwrapIfNullable() &&
4449
(node.Operand is MemberExpression || node.Operand is QuerySourceReferenceExpression))
4550
{
4651
return AddAndConvertExpression(node.Operand, node.Type);
@@ -75,4 +80,4 @@ private Expression AddAndConvertExpression(Expression expression, System.Type ty
7580
type);
7681
}
7782
}
78-
}
83+
}

0 commit comments

Comments
 (0)