Try this and see if it resolves your problem
(change MyCompany.MyProduct appropriately ...)
Code:
using System;
using System.Collections;
using System.Data;
using NH = NHibernate;
namespace MyCompany.MyProduct.NHibernate.CustomTypes
{
public class StringFixedLengthType : NH::Type.CustomType
{
private static StringFixedLengthType _instance;
public static StringFixedLengthType Instance
{
get { return _instance; }
}
static StringFixedLengthType()
{
_instance = new StringFixedLengthType();
}
protected StringFixedLengthType() : base(typeof(MyCompany.MyProduct.NHibernate.UserTypes.StringFixedLengthType), new Hashtable())
{
}
}
}
namespace MyCompany.MyProduct.NHibernate.UserTypes
{
/// <summary>
/// An <see cref="NH.UserTypes.IUserType"/> that reads a <c>null</c> value from an <c>StringFixedLength</c>
/// column in the database as a <see cref="String.Empty">String.Empty</see>
/// and writes a <see cref="String.Empty">String.Empty</see> to the database
/// as <c>null</c>. Trailing blanks are left as is when getting and setting
/// from and to the database, but are ignored in comparison for equality.
/// </summary>
/// <remarks>
/// This is intended to help with Windows Forms DataBinding and the problems associated
/// with binding a null value. See <a href="http://jira.nhibernate.org/browse/NH-279">
/// NH-279</a> for the origin of this code.
/// </remarks>
public class StringFixedLengthType : NH::UserTypes.IUserType
{
#region Fields
private static NH::Type.StringType _stringType;
private static NH::SqlTypes.StringFixedLengthSqlType _stringFixedLengthSqlType;
private static NH::SqlTypes.SqlType[] _sqlTypes;
private static System.Data.DbType[] _dbTypes;
#endregion
#region Properties
protected static NH::Type.StringType StringType
{
get { return _stringType; }
}
#endregion
#region Constructors
static StringFixedLengthType()
{
_stringType = (NH.Type.StringType)NH::NHibernateUtil.String;
_stringFixedLengthSqlType = new NH::SqlTypes.StringFixedLengthSqlType();
_sqlTypes = new NH::SqlTypes.SqlType[] { _stringFixedLengthSqlType };
_dbTypes = new System.Data.DbType[] { System.Data.DbType.StringFixedLength };
}
public StringFixedLengthType()
{
}
#endregion
#region IUserType Members
bool NH::UserTypes.IUserType.Equals(object x, object y)
{
if (object.ReferenceEquals(x, y))
{
return true;
}
string stringX =
(x == null || x == DBNull.Value ? String.Empty : x.ToString().TrimEnd());
string stringY =
(y == null || y == DBNull.Value ? String.Empty : y.ToString().TrimEnd());
bool result = (string.Compare(stringX, stringY) == 0);
return result;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public NH::SqlTypes.SqlType[] SqlTypes
{
get
{
return _sqlTypes;
}
}
public System.Data.DbType[] DbTypes
{
get
{
return _dbTypes;
}
}
public object DeepCopy(object value)
{
return value;
}
public virtual void NullSafeSet(IDbCommand cmd, object value, int index)
{
_stringType.NullSafeSet(cmd, value, index);
}
public System.Type ReturnedType
{
get
{
return typeof(string);
}
}
public virtual object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
{
return _stringType.NullSafeGet(rs, names);
}
public bool IsMutable
{
get
{
return false;
}
}
public virtual int GetHashCode(object obj)
{
return obj.GetHashCode();
}
#endregion
}
}
Then whenever you set a query parameter, instead of doing just this:
Code:
query.SetParameter(parameter.Name, parameter.Value);
You have to do this:
Code:
if (parameter.Type == typeof(string))
{
query.SetParameter(parameter.Name, parameter.Value,
MyCompany.MyProduct.NHibernate.CustomTypes.StringFixedLengthType.Instance);
}
else
{
query.SetParameter(parameter.Name, parameter.Value);
}
Fortunately we have front-ends to NHibernate query objects and parameters, so this is encapsulated for us ...
I guess the question is then, since you're having a problem with parameters in SQL statements that NHibernate automatically generates behind the scenes, does take the mapped custom type into account when it sets parameters on these internally generated SQL statements or not. If not, then someone else will need to look into this further. Ultimately what needs to happen is the SQL command parameters must be built like this:
Code:
OracleParameter parameter = new Oracle.DataAccess.Client.OracleParameter(parameterName, Oracle.DataAccess.Client.OracleDbType.NChar);