Skip to content

Commit 42c5b85

Browse files
committed
additional case-insesitive field and/or property macthing
1 parent 57ec315 commit 42c5b85

File tree

6 files changed

+203
-11
lines changed

6 files changed

+203
-11
lines changed

src/NHibernate.Test/TransformTests/AliasToBeanResultTransformerFixture.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ public struct TestStruct
4141
public string Something { get; set; }
4242
}
4343

44+
public class PublicPropertiesSimpleDTO
45+
{
46+
public int Id { get; set; }
47+
public string Name { get; set; }
48+
}
49+
50+
public class PrivateFieldsSimpleDTO
51+
{
52+
private int id;
53+
private string name;
54+
55+
public int Id { get { return id; } }
56+
public string Name { get { return name; } }
57+
}
58+
4459
#region Overrides of TestCase
4560

4661
protected override IList Mappings
@@ -77,6 +92,52 @@ public void WorkWithOutPublicParameterLessCtor()
7792
}
7893
}
7994

95+
[Test]
96+
public void ToPublicProperties_WithoutAnyProjections()
97+
{
98+
try
99+
{
100+
Setup();
101+
102+
using (ISession s = OpenSession())
103+
{
104+
var transformer = Transformers.AliasToBean<PublicPropertiesSimpleDTO>();
105+
IList<PublicPropertiesSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
106+
.SetResultTransformer(transformer)
107+
.List<PublicPropertiesSimpleDTO>();
108+
Assert.That(l.Count, Is.EqualTo(2));
109+
Assert.That(l, Has.All.Not.Null);
110+
}
111+
}
112+
finally
113+
{
114+
Cleanup();
115+
}
116+
}
117+
118+
[Test]
119+
public void ToPrivateFields_WithoutAnyProjections()
120+
{
121+
try
122+
{
123+
Setup();
124+
125+
using (ISession s = OpenSession())
126+
{
127+
var transformer = Transformers.AliasToBean<PrivateFieldsSimpleDTO>();
128+
IList<PrivateFieldsSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
129+
.SetResultTransformer(transformer)
130+
.List<PrivateFieldsSimpleDTO>();
131+
Assert.That(l.Count, Is.EqualTo(2));
132+
Assert.That(l, Has.All.Not.Null);
133+
}
134+
}
135+
finally
136+
{
137+
Cleanup();
138+
}
139+
}
140+
80141
[Test]
81142
public void WorkWithPublicParameterLessCtor()
82143
{

src/NHibernate/NHibernate.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@
670670
<Compile Include="Transform\AliasToEntityMapResultTransformer.cs" />
671671
<Compile Include="Transform\CacheableResultTransformer.cs" />
672672
<Compile Include="Transform\AliasedTupleSubsetResultTransformer.cs" />
673+
<Compile Include="Transform\CaseInsensitiveFieldAccessor.cs" />
674+
<Compile Include="Transform\CaseInsensitivePropertyAccessor.cs" />
673675
<Compile Include="Transform\ITupleSubsetResultTransformer.cs" />
674676
<Compile Include="Transform\DistinctRootEntityResultTransformer.cs" />
675677
<Compile Include="Transform\IResultTransformer.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/Transform/AliasToBeanResultTransformer.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,25 @@ public AliasToBeanResultTransformer(System.Type resultClass)
4848
if (constructor == null && resultClass.IsClass)
4949
{
5050
throw new ArgumentException("The target class of a AliasToBeanResultTransformer need a parameter-less constructor",
51-
"resultClass");
51+
"resultClass");
5252
}
5353

54-
propertyAccessor =
55-
new ChainedPropertyAccessor(new[]
56-
{
57-
PropertyAccessorFactory.GetPropertyAccessor(null),
58-
PropertyAccessorFactory.GetPropertyAccessor("field")
59-
});
54+
var accessors = new[]
55+
{
56+
PropertyAccessorFactory.GetPropertyAccessor(null),
57+
PropertyAccessorFactory.GetPropertyAccessor("field"),
58+
// The following are added to support dialects that returns column names in different casing
59+
new CaseInsensitivePropertyAccessor(),
60+
new CaseInsensitiveFieldAccessor()
61+
};
62+
propertyAccessor = new ChainedPropertyAccessor(accessors);
6063
}
6164

6265

6366
public override bool IsTransformedValueATupleElement(String[] aliases, int tupleLength)
6467
{
6568
return false;
66-
}
69+
}
6770

6871

6972
public override object TransformTuple(object[] tuple, String[] aliases)
@@ -88,11 +91,11 @@ public override object TransformTuple(object[] tuple, String[] aliases)
8891
}
8992
}
9093
}
91-
94+
9295
// if resultClass is not a class but a value type, we need to use Activator.CreateInstance
9396
result = resultClass.IsClass
94-
? constructor.Invoke(null)
95-
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);
97+
? constructor.Invoke(null)
98+
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);
9699

97100
for (int i = 0; i < aliases.Length; i++)
98101
{
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Reflection;
2+
using NHibernate.Properties;
3+
4+
namespace NHibernate.Transform
5+
{
6+
/// <summary>
7+
/// Access a private field found by ignoring case matching
8+
/// </summary>
9+
public class CaseInsensitiveFieldAccessor : IPropertyAccessor
10+
{
11+
#region IPropertyAccessor Members
12+
13+
public IGetter GetGetter(System.Type theClass, string propertyName)
14+
{
15+
return new FieldAccessor.FieldGetter(GetField(theClass, propertyName), theClass, propertyName);
16+
}
17+
18+
public ISetter GetSetter(System.Type theClass, string propertyName)
19+
{
20+
return new FieldAccessor.FieldSetter(GetField(theClass, propertyName), theClass, propertyName);
21+
}
22+
23+
public bool CanAccessThroughReflectionOptimizer
24+
{
25+
get { return true; }
26+
}
27+
28+
#endregion
29+
30+
private static FieldInfo GetField(System.Type type, string fieldName)
31+
{
32+
return GetField(type, fieldName, type);
33+
}
34+
35+
private static FieldInfo GetField(System.Type type, string fieldName, System.Type originalType)
36+
{
37+
if (type == null || type == typeof(object))
38+
{
39+
throw new PropertyNotFoundException(originalType, fieldName);
40+
}
41+
42+
var bindingFlags = BindingFlags.Instance |
43+
BindingFlags.Public |
44+
BindingFlags.NonPublic |
45+
BindingFlags.DeclaredOnly |
46+
BindingFlags.IgnoreCase;
47+
48+
var result = type.GetField(fieldName, bindingFlags);
49+
if (result == null)
50+
{
51+
result = GetField(type.BaseType, fieldName, originalType);
52+
}
53+
54+
return result;
55+
}
56+
}
57+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Linq;
2+
using System.Reflection;
3+
using NHibernate.Properties;
4+
5+
namespace NHibernate.Transform
6+
{
7+
/// <summary>
8+
/// Access a Property found by ignoring case matching
9+
/// </summary>
10+
public class CaseInsensitivePropertyAccessor : IPropertyAccessor
11+
{
12+
#region IPropertyAccessor Members
13+
14+
public IGetter GetGetter(System.Type theClass, string propertyName)
15+
{
16+
var property = GetProperty(theClass, propertyName);
17+
if (property == null)
18+
throw new PropertyNotFoundException(theClass, propertyName);
19+
return new BasicPropertyAccessor.BasicGetter(theClass, property, propertyName);
20+
}
21+
22+
public ISetter GetSetter(System.Type theClass, string propertyName)
23+
{
24+
var property = GetProperty(theClass, propertyName);
25+
if (property == null)
26+
throw new PropertyNotFoundException(theClass, propertyName);
27+
return new BasicPropertyAccessor.BasicSetter(theClass, property, propertyName);
28+
}
29+
30+
public bool CanAccessThroughReflectionOptimizer
31+
{
32+
get { return true; }
33+
}
34+
35+
#endregion
36+
37+
private static PropertyInfo GetProperty(System.Type type, string propertyName)
38+
{
39+
PropertyInfo result = null;
40+
if (type == typeof(object) || type == null)
41+
{
42+
return result;
43+
}
44+
45+
var bindingFlags = BindingFlags.Instance |
46+
BindingFlags.Public |
47+
BindingFlags.NonPublic |
48+
BindingFlags.DeclaredOnly |
49+
BindingFlags.IgnoreCase;
50+
51+
result = type.GetProperties(bindingFlags)
52+
.FirstOrDefault(p => string.Compare(p.Name, propertyName, true) == 0);
53+
54+
if (result == null)
55+
result = GetProperty(type.BaseType, propertyName);
56+
else
57+
if (!result.CanWrite)
58+
result = null;
59+
60+
return result;
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)