Mapping a DateTime property to an Int64 ticks column using NHibernate
I'm using Fluent NHibernate to map to an Oracle database table.
The table has a number column that represents a date. The number represents the number of ticks, so the conversion is pretty straightforward. I can't change the type to an Oracle date type because other applications use the same database.
I'd like to have a DateTime property in my model class:
public virtual DateTime Time { get; set; }
and map it to the ticks column. I tried to use
.CustomType(typeof(long))
but it didn't work so well, NHibernate threw a System.InvalidCastException (my guess is that there was a problem casting between an Int64 and a DateTime).
Must I i开发者_Python百科mplement an IUserType, or is there a simpler way?
Perhaps an IUserType would help, but I've never done this myself.
What you can do, as a workaround is this:
Create 2 properties in your class:
- one public property that is a DateTime
one private property that holds a TimeSpan
private TimeSpan Ts { get; set; }
public DateTime TheDate { get { return new DateTime (Ts.Ticks); } set { Ts = new TimeSpan (value.Ticks); } }
Map the private property in your NHibernate mapping to the specific column in the database, so that NHibernate can save and retrieve the value. The public DateTime property just accesses the TimeSpan property, and converts the Timespan to a DateTime in its getter, and sets the Timespan (convert datetime to timespan) in its setter.
The only disadvantage of this workaround, is that you cannot use the DateTime property in your queries. (Unless you map this property as well, and specify that NHibernate should not save this property, but I'm not sure if this is possible).
Just as follow up, here's an example of a UserType which handles this:
public class DateTimeToTicksUserType : IUserType
{
public object Assemble(object cached, object owner)
{
return cached;
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return value;
}
public new bool Equals(object x, object y)
{
if (x == null) return false;
return x.Equals(y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public bool IsMutable
{
get { return false; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
object value = NHibernateUtil.Int64.NullSafeGet(rs, names);
if (value == null)
{
return null;
}
return new DateTime((long) value);
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
NHibernateUtil.Int64.NullSafeSet(cmd, null, index);
return;
}
value = ((DateTime) value).Ticks;
NHibernateUtil.Int64.NullSafeSet(cmd, value, index);
}
public object Replace(object original, object target, object owner)
{
return original;
}
public Type ReturnedType
{
get { return typeof (DateTime); }
}
public SqlType[] SqlTypes
{
get { return new[] {new SqlType(DbType.Int64)}; }
}
}
Eventually I implemented an IUserType. With the help of some examples I found on the web, it was pretty straightforward.
精彩评论