Skip to content

Commit 9491f57

Browse files
amroelfredericDelaporte
authored andcommitted
NH-3693 - test cases and fix for alias to bean failures with Firebird
1 parent 6ae30d5 commit 9491f57

File tree

7 files changed

+197
-33
lines changed

7 files changed

+197
-33
lines changed

src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ private void AssertObjectsAreEqual(object expected, object actual, string name)
128128

129129
if ((expectedType.IsValueType)
130130
|| (expected is System.Type)
131-
|| (expected is string))
131+
|| (expected is string)
132+
|| (expected is FieldInfo)
133+
|| (expected is PropertyInfo))
132134
{
133135
Assert.AreEqual(expected, actual, fieldPath);
134136
_fieldPath.Pop();

src/NHibernate.Test/TransformTests/AliasToBeanResultTransformerFixture.cs

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Collections;
32
using System.Collections.Generic;
43
using NHibernate.Transform;
@@ -41,6 +40,43 @@ public struct TestStruct
4140
public string Something { get; set; }
4241
}
4342

43+
public class PublicPropertiesSimpleDTO
44+
{
45+
public object Id { get; set; }
46+
public string Name { get; set; }
47+
}
48+
49+
public class PrivateFieldsSimpleDTO
50+
{
51+
private object id;
52+
private string name;
53+
54+
public object Id { get { return id; } }
55+
public string Name { get { return name; } }
56+
}
57+
58+
public class BasePublicPropsSimpleDTO
59+
{
60+
public object Id { get; set; }
61+
}
62+
63+
public class PublicInheritedPropertiesSimpleDTO : BasePublicPropsSimpleDTO
64+
{
65+
public string Name { get; set; }
66+
}
67+
68+
public class BasePrivateFieldSimpleDTO
69+
{
70+
private object id;
71+
public object Id { get { return id; } }
72+
}
73+
74+
public class PrivateInheritedFieldsSimpleDTO : BasePrivateFieldSimpleDTO
75+
{
76+
private string name;
77+
public string Name { get { return name; } }
78+
}
79+
4480
#region Overrides of TestCase
4581

4682
protected override IList Mappings
@@ -77,6 +113,99 @@ public void WorkWithOutPublicParameterLessCtor()
77113
}
78114
}
79115

116+
[Test]
117+
public void ToPublicProperties_WithoutAnyProjections()
118+
{
119+
try
120+
{
121+
Setup();
122+
123+
using (ISession s = OpenSession())
124+
{
125+
var transformer = Transformers.AliasToBean<PublicPropertiesSimpleDTO>();
126+
IList<PublicPropertiesSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
127+
.SetResultTransformer(transformer)
128+
.List<PublicPropertiesSimpleDTO>();
129+
Assert.That(l.Count, Is.EqualTo(2));
130+
Assert.That(l, Has.All.Not.Null);
131+
}
132+
}
133+
finally
134+
{
135+
Cleanup();
136+
}
137+
}
138+
139+
[Test]
140+
public void ToPrivateFields_WithoutAnyProjections()
141+
{
142+
try
143+
{
144+
Setup();
145+
146+
using (ISession s = OpenSession())
147+
{
148+
var transformer = Transformers.AliasToBean<PrivateFieldsSimpleDTO>();
149+
IList<PrivateFieldsSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
150+
.SetResultTransformer(transformer)
151+
.List<PrivateFieldsSimpleDTO>();
152+
Assert.That(l.Count, Is.EqualTo(2));
153+
Assert.That(l, Has.All.Not.Null);
154+
}
155+
}
156+
finally
157+
{
158+
Cleanup();
159+
}
160+
}
161+
162+
[Test]
163+
public void ToInheritedPublicProperties_WithoutProjections()
164+
{
165+
try
166+
{
167+
Setup();
168+
169+
using (ISession s = OpenSession())
170+
{
171+
var transformer = Transformers.AliasToBean<PublicInheritedPropertiesSimpleDTO>();
172+
IList<PublicInheritedPropertiesSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
173+
.SetResultTransformer(transformer)
174+
.List<PublicInheritedPropertiesSimpleDTO>();
175+
Assert.That(l.Count, Is.EqualTo(2));
176+
Assert.That(l, Has.All.Not.Null);
177+
}
178+
}
179+
finally
180+
{
181+
Cleanup();
182+
}
183+
}
184+
185+
[Test]
186+
public void ToInheritedPrivateFields_WithoutProjections()
187+
{
188+
try
189+
{
190+
Setup();
191+
192+
using (ISession s = OpenSession())
193+
{
194+
var transformer = Transformers.AliasToBean<PrivateInheritedFieldsSimpleDTO>();
195+
IList<PrivateInheritedFieldsSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
196+
.SetResultTransformer(transformer)
197+
.List<PrivateInheritedFieldsSimpleDTO>();
198+
Assert.That(l.Count, Is.EqualTo(2));
199+
Assert.That(l, Has.All.Not.Null);
200+
Assert.That(l, Has.All.Property("Id").Not.Null);
201+
}
202+
}
203+
finally
204+
{
205+
Cleanup();
206+
}
207+
}
208+
80209
[Test]
81210
public void WorkWithPublicParameterLessCtor()
82211
{

src/NHibernate/NHibernate.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@
677677
<Compile Include="Transform\ITupleSubsetResultTransformer.cs" />
678678
<Compile Include="Transform\DistinctRootEntityResultTransformer.cs" />
679679
<Compile Include="Transform\IResultTransformer.cs" />
680+
<Compile Include="Transform\QueryAliasToObjectPropertySetter.cs" />
680681
<Compile Include="Transform\RootEntityResultTransformer.cs" />
681682
<Compile Include="TransientObjectException.cs" />
682683
<Compile Include="Type\AbstractType.cs" />

src/NHibernate/Properties/BasicPropertyAccessor.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ internal static BasicSetter GetSetterOrNull(System.Type type, string propertyNam
130130
return null;
131131
}
132132

133+
// According to http://msdn.microsoft.com/EN-US/library/kz0a8sxy%28v=VS.110,d=hv.2%29.aspx
134+
// the assumption articulated in the comment following "if(type.IsValueType)" is wrong at least since .NET 2.0!
135+
// This part of the code has beed changed twice to fix the following Issues in order: NH-1728 then NH-1904
136+
// As it stands now the implementation prevents AliasToBeanTransformer from finding the correct property
137+
// on a class if the dialect returns column names in a different case than expected.
138+
133139
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
134140

135141
if (type.IsValueType)

src/NHibernate/Properties/ChainedPropertyAccessor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace NHibernate.Properties
44
{
5+
// To be removed in v6.0
56
[Serializable]
7+
[Obsolete("This class has no more usages in NHibernate and will be removed in a future version.")]
68
public class ChainedPropertyAccessor : IPropertyAccessor
79
{
810
private readonly IPropertyAccessor[] chain;

src/NHibernate/Transform/AliasToBeanResultTransformer.cs

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections;
33
using System.Reflection;
4-
using NHibernate.Properties;
54

65
namespace NHibernate.Transform
76
{
@@ -27,10 +26,9 @@ namespace NHibernate.Transform
2726
[Serializable]
2827
public class AliasToBeanResultTransformer : AliasedTupleSubsetResultTransformer
2928
{
29+
private readonly QueryAliasToObjectPropertySetter _propertySetter;
3030
private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
3131
private readonly System.Type resultClass;
32-
private ISetter[] setters;
33-
private readonly IPropertyAccessor propertyAccessor;
3432
private readonly ConstructorInfo constructor;
3533

3634
public AliasToBeanResultTransformer(System.Type resultClass)
@@ -48,22 +46,17 @@ public AliasToBeanResultTransformer(System.Type resultClass)
4846
if (constructor == null && resultClass.IsClass)
4947
{
5048
throw new ArgumentException("The target class of a AliasToBeanResultTransformer need a parameter-less constructor",
51-
"resultClass");
49+
"resultClass");
5250
}
5351

54-
propertyAccessor =
55-
new ChainedPropertyAccessor(new[]
56-
{
57-
PropertyAccessorFactory.GetPropertyAccessor(null),
58-
PropertyAccessorFactory.GetPropertyAccessor("field")
59-
});
52+
_propertySetter = QueryAliasToObjectPropertySetter.MakeFor(resultClass);
6053
}
6154

6255

6356
public override bool IsTransformedValueATupleElement(String[] aliases, int tupleLength)
6457
{
6558
return false;
66-
}
59+
}
6760

6861

6962
public override object TransformTuple(object[] tuple, String[] aliases)
@@ -76,30 +69,13 @@ public override object TransformTuple(object[] tuple, String[] aliases)
7669

7770
try
7871
{
79-
if (setters == null)
80-
{
81-
setters = new ISetter[aliases.Length];
82-
for (int i = 0; i < aliases.Length; i++)
83-
{
84-
string alias = aliases[i];
85-
if (alias != null)
86-
{
87-
setters[i] = propertyAccessor.GetSetter(resultClass, alias);
88-
}
89-
}
90-
}
91-
92-
// if resultClass is not a class but a value type, we need to use Activator.CreateInstance
9372
result = resultClass.IsClass
94-
? constructor.Invoke(null)
95-
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);
73+
? constructor.Invoke(null)
74+
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);
9675

9776
for (int i = 0; i < aliases.Length; i++)
9877
{
99-
if (setters[i] != null)
100-
{
101-
setters[i].Set(result, tuple[i]);
102-
}
78+
_propertySetter.SetProperty(aliases[i], tuple[i], result);
10379
}
10480
}
10581
catch (InstantiationException e)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
namespace NHibernate.Transform
7+
{
8+
[Serializable]
9+
public class QueryAliasToObjectPropertySetter
10+
{
11+
private readonly IEnumerable<FieldInfo> _fields;
12+
private readonly IEnumerable<PropertyInfo> _properties;
13+
14+
private QueryAliasToObjectPropertySetter(FieldInfo[] fields, PropertyInfo[] properties)
15+
{
16+
_fields = fields;
17+
_properties = properties;
18+
}
19+
20+
public static QueryAliasToObjectPropertySetter MakeFor(System.Type objType)
21+
{
22+
var bindingFlags = BindingFlags.Instance |
23+
BindingFlags.Public |
24+
BindingFlags.NonPublic |
25+
BindingFlags.IgnoreCase;
26+
var fields = objType.GetFields(bindingFlags);
27+
var properties = objType.GetProperties(bindingFlags);
28+
29+
return new QueryAliasToObjectPropertySetter(fields, properties);
30+
}
31+
32+
public void SetProperty(string alias, object value, object resultObj)
33+
{
34+
var property = _properties.SingleOrDefault(prop => string.Equals(prop.Name, alias, StringComparison.OrdinalIgnoreCase));
35+
var field = _fields.SingleOrDefault(prop => string.Equals(prop.Name, alias, StringComparison.OrdinalIgnoreCase));
36+
if (field == null && property == null)
37+
throw new PropertyNotFoundException(resultObj.GetType(), alias, "setter");
38+
39+
if (field != null)
40+
{
41+
field.SetValue(resultObj, value);
42+
return;
43+
}
44+
if (property != null && property.CanWrite)
45+
property.SetValue(resultObj, value, new object[0]);
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)