Created
January 13, 2012 21:34
-
-
Save drlongnecker/1608818 to your computer and use it in GitHub Desktop.
Addressing issues in Oracle.DataAccess and AliasToBeanTransformer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Serializable] | |
public class OracleSQLAliasToBeanTransformer : IResultTransformer | |
{ | |
const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; | |
readonly System.Type _resultClass; | |
ISetter[] _setters; | |
readonly IPropertyAccessor _propertyAccessor; | |
readonly ConstructorInfo _constructor; | |
readonly PropertyInfo[] _fields; | |
public OracleSQLAliasToBeanTransformer(Type resultClass) | |
{ | |
if (resultClass == null) | |
{ | |
throw new ArgumentNullException("resultClass"); | |
} | |
this._resultClass = resultClass; | |
_constructor = resultClass.GetConstructor(Flags, null, Type.EmptyTypes, null); | |
// if resultClass is a ValueType (struct), GetConstructor will return null... | |
// in that case, we'll use Activator.CreateInstance instead of the ConstructorInfo to create instances | |
if (_constructor == null && resultClass.IsClass) | |
{ | |
throw new ArgumentException("The target class of a AliasToBeanResultTransformer " | |
+"needs a parameter-less constructor.", "resultClass"); | |
} | |
_propertyAccessor = new ChainedPropertyAccessor(new[] | |
{ | |
PropertyAccessorFactory.GetPropertyAccessor(null), | |
PropertyAccessorFactory.GetPropertyAccessor("field"), | |
}); | |
// this is also a PERSONAL preference to only return fields that have a valid setter. | |
_fields = this._resultClass.GetProperties(Flags).Where(x => x.GetSetMethod() != null).ToArray(); | |
} | |
public object TransformTuple(object[] tuple, String[] aliases) | |
{ | |
// fix issue #1: aliases in Oracle CreateSQLQuery | |
// returns all UPPERCASE no matter your object case. | |
// Using the fields generated in the constructor. | |
if (_fields == null) | |
{ | |
throw new ArgumentNullException("fields"); | |
} | |
// this seems to address a similar issue: | |
// https://hibernate.onjira.com/browse/HHH-2304 | |
// which also appears to exist in NHibernate | |
var fieldNames = _fields.Select(x => x.Name).ToList(); | |
for (var i = 0; i < fieldNames.Count; i++) | |
{ | |
var fieldType = _fields[i].PropertyType; | |
if (fieldType.IsEnum) | |
{ | |
// It can't seem to handle enums, so convert them | |
// to Int (so the enum will work) | |
tuple[i] = Convert.ChangeType(tuple[i], TypeCode.Int32); | |
} | |
else | |
{ | |
// set it to the actual field type on the property we're | |
// filling. | |
tuple[i] = Convert.ChangeType(tuple[i], fieldType); | |
} | |
} | |
object result; | |
try | |
{ | |
if (_setters == null) | |
{ | |
_setters = new ISetter[fieldNames.Count]; | |
for (var i = 0; i < fieldNames.Count; i++) | |
{ | |
var fieldName = fieldNames[i]; | |
_setters[i] = _propertyAccessor.GetSetter(_resultClass, fieldName); | |
} | |
} | |
// if resultClass is not a class but a value type, we need to use Activator.CreateInstance | |
result = _resultClass.IsClass | |
? _constructor.Invoke(null) | |
: NHibernate.Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(_resultClass, true); | |
for (var i = 0; i < fieldNames.Count; i++) | |
{ | |
if (_setters[i] != null) | |
{ | |
_setters[i].Set(result, tuple[i]); | |
} | |
} | |
} | |
catch (InstantiationException e) | |
{ | |
throw new HibernateException("Could not instantiate result class: " + _resultClass.FullName, e); | |
} | |
catch (MethodAccessException e) | |
{ | |
throw new HibernateException("Could not instantiate result class: " + _resultClass.FullName, e); | |
} | |
return result; | |
} | |
public IList TransformList(IList collection) | |
{ | |
return collection; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment