diff --git a/src/NHibernate.Test/Async/Linq/EnumTests.cs b/src/NHibernate.Test/Async/Linq/EnumTests.cs index 21f23a84c8b..c869012844c 100644 --- a/src/NHibernate.Test/Async/Linq/EnumTests.cs +++ b/src/NHibernate.Test/Async/Linq/EnumTests.cs @@ -9,6 +9,7 @@ using System; +using System.Collections.Generic; using System.Linq; using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping.ByCode; @@ -50,9 +51,24 @@ protected override HbmMapping GetMappings() m.Type(_enumType); m.Formula($"(case when Enum1 = {_unspecifiedValue} then null else Enum1 end)"); }); + rc.Bag(x => x.Children, m => + { + m.Cascade(Mapping.ByCode.Cascade.All); + m.Inverse(true); + }, + a => a.OneToMany() + ); rc.ManyToOne(x => x.Other, m => m.Cascade(Mapping.ByCode.Cascade.All)); }); + mapper.Class( + rc => + { + rc.Table("EnumEntityChild"); + rc.Id(x => x.Id, m => m.Generator(Generators.Guid)); + rc.Property(x => x.Name); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); } @@ -184,5 +200,25 @@ public async Task CanQueryComplexExpressionOnTestEnumAsync() Assert.That(query.Count, Is.EqualTo(0)); } } + + [Test] + public async Task CanProjectWithListTransformationAsync() + { + using (var session = OpenSession()) + using (var trans = session.BeginTransaction()) + { + var entities = session.Query(); + + var query = await (entities.Select(user => new + { + user.Name, + simple = user.Enum1, + children = user.Children, + nullableEnum1IsLarge = user.NullableEnum1 == TestEnum.Large + }).ToListAsync()); + + Assert.That(query.Count, Is.EqualTo(10)); + } + } } } diff --git a/src/NHibernate.Test/Linq/EnumTests.cs b/src/NHibernate.Test/Linq/EnumTests.cs index 1b01c1706d7..21adf84bf3a 100644 --- a/src/NHibernate.Test/Linq/EnumTests.cs +++ b/src/NHibernate.Test/Linq/EnumTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping.ByCode; @@ -37,9 +38,24 @@ protected override HbmMapping GetMappings() m.Type(_enumType); m.Formula($"(case when Enum1 = {_unspecifiedValue} then null else Enum1 end)"); }); + rc.Bag(x => x.Children, m => + { + m.Cascade(Mapping.ByCode.Cascade.All); + m.Inverse(true); + }, + a => a.OneToMany() + ); rc.ManyToOne(x => x.Other, m => m.Cascade(Mapping.ByCode.Cascade.All)); }); + mapper.Class( + rc => + { + rc.Table("EnumEntityChild"); + rc.Id(x => x.Id, m => m.Generator(Generators.Guid)); + rc.Property(x => x.Name); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); } @@ -171,6 +187,26 @@ public void CanQueryComplexExpressionOnTestEnum() Assert.That(query.Count, Is.EqualTo(0)); } } + + [Test] + public void CanProjectWithListTransformation() + { + using (var session = OpenSession()) + using (var trans = session.BeginTransaction()) + { + var entities = session.Query(); + + var query = entities.Select(user => new + { + user.Name, + simple = user.Enum1, + children = user.Children, + nullableEnum1IsLarge = user.NullableEnum1 == TestEnum.Large + }).ToList(); + + Assert.That(query.Count, Is.EqualTo(10)); + } + } } public class EnumEntity @@ -181,7 +217,17 @@ public class EnumEntity public virtual TestEnum Enum1 { get; set; } public virtual TestEnum? NullableEnum1 { get; set; } + public virtual int? NullableInt { get; set; } + public virtual EnumEntity Other { get; set; } + + public virtual IList Children { get; set; } = new List(); + } + + public class EnumEntityChild + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } } public enum TestEnum diff --git a/src/NHibernate/Linq/NestedSelects/SelectClauseRewriter.cs b/src/NHibernate/Linq/NestedSelects/SelectClauseRewriter.cs index dae294cb48d..29275888af6 100644 --- a/src/NHibernate/Linq/NestedSelects/SelectClauseRewriter.cs +++ b/src/NHibernate/Linq/NestedSelects/SelectClauseRewriter.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq.Expressions; +using NHibernate.Util; using Remotion.Linq.Clauses.Expressions; using Remotion.Linq.Parsing; @@ -41,6 +42,10 @@ public override Expression Visit(Expression expression) protected override Expression VisitUnary(UnaryExpression node) { if (node.NodeType == ExpressionType.Convert && + // We can skip a convert node only when the underlying types are equal otherwise it + // will throw an exception when trying to convert the value from an object + // (e.g. (int?)(Enum?) input[0] -> (Enum?) cast cannot be skipped) + node.Type.UnwrapIfNullable() == node.Operand.Type.UnwrapIfNullable() && (node.Operand is MemberExpression || node.Operand is QuerySourceReferenceExpression)) { return AddAndConvertExpression(node.Operand, node.Type); @@ -75,4 +80,4 @@ private Expression AddAndConvertExpression(Expression expression, System.Type ty type); } } -} \ No newline at end of file +}