Skip to content

Commit 24c5de6

Browse files
committed
Fix InvalidCastException when casting a field of a type different than Enum's underlying type
Fixes #1121
1 parent 2b45b4c commit 24c5de6

File tree

5 files changed

+209
-1
lines changed

5 files changed

+209
-1
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NUnit.Framework;
13+
using NHibernate.Linq;
14+
15+
namespace NHibernate.Test.NHSpecificTest.GH1121
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnSetUp()
22+
{
23+
using (var session = OpenSession())
24+
using (var transaction = session.BeginTransaction())
25+
{
26+
session.Save(new Entity
27+
{
28+
Name = "Bob",
29+
Color = 2
30+
});
31+
32+
transaction.Commit();
33+
}
34+
}
35+
36+
protected override void OnTearDown()
37+
{
38+
using (var session = OpenSession())
39+
using (var transaction = session.BeginTransaction())
40+
{
41+
session.CreateQuery("delete from Entity").ExecuteUpdate();
42+
43+
transaction.Commit();
44+
}
45+
}
46+
47+
[Test]
48+
public async Task CanCastToDifferentTypeAsync()
49+
{
50+
using (var session = OpenSession())
51+
using (session.BeginTransaction())
52+
{
53+
var result = await ((
54+
from e in session.Query<Entity>()
55+
where e.Name == "Bob"
56+
select new
57+
{
58+
e.Id,
59+
MyColor = (int) e.Color
60+
}).ToListAsync());
61+
62+
Assert.That(result, Has.Count.EqualTo(1));
63+
Assert.That(result[0].MyColor, Is.EqualTo(2));
64+
}
65+
}
66+
67+
[Test]
68+
public async Task CanCastEnumWithDifferentUnderlyingTypeAsync()
69+
{
70+
using (var session = OpenSession())
71+
using (session.BeginTransaction())
72+
{
73+
var result = await ((
74+
from e in session.Query<Entity>()
75+
where e.Name == "Bob"
76+
select new
77+
{
78+
e.Id,
79+
MyColor = (Colors) e.Color
80+
}).ToListAsync());
81+
82+
Assert.That(result, Has.Count.EqualTo(1));
83+
Assert.That(result[0].MyColor, Is.EqualTo(Colors.Green));
84+
}
85+
}
86+
}
87+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH1121
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
public virtual long Color { get; set; }
10+
}
11+
public enum Colors
12+
{
13+
Red = 1,
14+
Green = 2,
15+
Blue = 3,
16+
}
17+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH1121
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
protected override void OnSetUp()
10+
{
11+
using (var session = OpenSession())
12+
using (var transaction = session.BeginTransaction())
13+
{
14+
session.Save(new Entity
15+
{
16+
Name = "Bob",
17+
Color = 2
18+
});
19+
20+
transaction.Commit();
21+
}
22+
}
23+
24+
protected override void OnTearDown()
25+
{
26+
using (var session = OpenSession())
27+
using (var transaction = session.BeginTransaction())
28+
{
29+
session.CreateQuery("delete from Entity").ExecuteUpdate();
30+
31+
transaction.Commit();
32+
}
33+
}
34+
35+
[Test]
36+
public void CanCastToDifferentType()
37+
{
38+
using (var session = OpenSession())
39+
using (session.BeginTransaction())
40+
{
41+
var result = (
42+
from e in session.Query<Entity>()
43+
where e.Name == "Bob"
44+
select new
45+
{
46+
e.Id,
47+
MyColor = (int) e.Color
48+
}).ToList();
49+
50+
Assert.That(result, Has.Count.EqualTo(1));
51+
Assert.That(result[0].MyColor, Is.EqualTo(2));
52+
}
53+
}
54+
55+
[Test]
56+
public void CanCastEnumWithDifferentUnderlyingType()
57+
{
58+
using (var session = OpenSession())
59+
using (session.BeginTransaction())
60+
{
61+
var result = (
62+
from e in session.Query<Entity>()
63+
where e.Name == "Bob"
64+
select new
65+
{
66+
e.Id,
67+
MyColor = (Colors) e.Color
68+
}).ToList();
69+
70+
Assert.That(result, Has.Count.EqualTo(1));
71+
Assert.That(result[0].MyColor, Is.EqualTo(Colors.Green));
72+
}
73+
}
74+
}
75+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.GH1121">
4+
5+
<class name="Entity">
6+
<id name="Id" generator="guid.comb"/>
7+
<property name="Name"/>
8+
<property name="Color"/>
9+
</class>
10+
</hibernate-mapping>

src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Linq.Expressions;
5+
using System.Reflection;
56
using NHibernate.Hql.Ast;
67
using NHibernate.Linq.Expressions;
8+
using NHibernate.Util;
79
using Remotion.Linq.Parsing;
810

911
namespace NHibernate.Linq.Visitors
@@ -83,12 +85,29 @@ public override Expression Visit(Expression expression)
8385
// Pure HQL evaluation
8486
_hqlTreeNodes.Add(_hqlVisitor.Visit(expression).AsExpression());
8587

86-
return Expression.Convert(Expression.ArrayIndex(_inputParameter, Expression.Constant(_iColumn++)), expression.Type);
88+
return Convert(Expression.ArrayIndex(_inputParameter, Expression.Constant(_iColumn++)), expression.Type);
8789
}
8890

8991
// Can't handle this node with HQL. Just recurse down, and emit the expression
9092
return base.Visit(expression);
9193
}
94+
95+
private static readonly MethodInfo ConvertChangeType =
96+
ReflectHelper.GetMethod(() => System.Convert.ChangeType(default(object), default(System.Type)));
97+
98+
private static Expression Convert(Expression expression, System.Type type)
99+
{
100+
//#1121
101+
if (type.IsEnum)
102+
{
103+
expression = Expression.Call(
104+
ConvertChangeType,
105+
expression,
106+
Expression.Constant(Enum.GetUnderlyingType(type)));
107+
}
108+
109+
return Expression.Convert(expression, type);
110+
}
92111
}
93112

94113
// Since v5

0 commit comments

Comments
 (0)