Skip to content

Instantly share code, notes, and snippets.

@drlongnecker
Created January 13, 2012 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drlongnecker/1608818 to your computer and use it in GitHub Desktop.
Save drlongnecker/1608818 to your computer and use it in GitHub Desktop.
Addressing issues in Oracle.DataAccess and AliasToBeanTransformer
[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