用于Oracle INTERVAL DAY TO SECOND数据类型的NHibernate映射

我挑战我的一位同事的问题并非如此,而是由DBA提出的。 我们在其中一个对象上有一个TimeSpan属性,该属性需要保留。 是的,您可以只从对象的Start和End DateTime属性推断出值,但DBA坚持要将此值保存在数据库表中。

因此,DBA选择保存该值的Oracle数据类型是INTERVAL DAY(2)TO SECOND(6)。

Oracle.DataAccess中的相应类型是OracleDbType.InvervalDS,但是我无法找到与如何使用NHibernate进行映射相关的任何内容。

我们最终得到了这个解决方案

public class SomeTimeSpanTestClass { public virtual string TimeSpanTest { get; protected set; } public virtual TimeSpan ActualTimeSpan { get { // Need to do some formatting of TimeSpanTest before it can be parsed return TimeSpan.Parse(TimeSpanTest); } set { TimeSpanTest = string.Format("{0}{1} {2}:{3}:{4}.{5}", value.ToString().Contains('-') ? "-" : "+", value.Days.ToString().Contains('-') ? value.Days.ToString().Substring(1).PadLeft(2, '0') : value.Days.ToString().PadLeft(2, '0'), value.Hours.ToString().Contains('-') ? value.Hours.ToString().Substring(1).PadLeft(2, '0') : value.Hours.ToString().PadLeft(2, '0'), value.Minutes.ToString().Contains('-') ? value.Minutes.ToString().Substring(1).PadLeft(2, '0') : value.Minutes.ToString().PadLeft(2, '0'), value.Seconds.ToString().Contains('-') ? value.Seconds.ToString().Substring(1).PadLeft(2, '0') : value.Seconds.ToString().PadLeft(2, '0'), value.Milliseconds.ToString().Contains('-') ? value.Milliseconds.ToString().Substring(1).PadLeft(6, '0') : value.Milliseconds.ToString().PadLeft(6, '0') ); } } } 

用映射为

   

一个非常低劣的测试

  class Program { static void Main(string[] args) { SomeTimeSpanTestClass spanClass = new SomeTimeSpanTestClass(); DateTime start = DateTime.Now; DateTime end = DateTime.Now.AddMinutes(75); spanClass.ActualTimeSpan = end.Subtract(start); Console.WriteLine(spanClass.TimeSpanTest); } } 

显然,这段代码没有以任何方式重构,但是为了这个测试的目的,它无论如何都是微不足道的。

数据库中的值基本上必须看起来像这样“+00 01:15:03.000874”。 如果值为负,则 – 字符在字符串的开头也有效。 这里需要注意的一点是:当值为负时,TimeSpan对象的每个部分在隔离查看时都是负数,因此不那么漂亮的“value.Days.ToString()。包含(’ – ‘)”in Format()方法的每个部分。

我们的测试通过,我们能够通过NHibernate将TimeSpan值保存并检索到定义为INTERVAL DAY(2)TO SECOND(6)的数据库列中。

如果有人在更好的方式之前完成了这个,我会非常有兴趣知道如何做。

抱歉没有链接Oracle类型,这是我的第一篇post所以我不被允许…

 public virtual TimeSpan ActualTimeSpan { get; set; } class TimeSpanUserType : ImmutableUserType { public override object NullSafeGet(IDataReader rs, string[] names, object owner) { // Need to do some formatting of TimeSpanTest before it can be parsed return TimeSpan.Parse((string)rs[names[0]]); } public override void NullSafeSet(IDbCommand cmd, object value, int index) { var timespan = (TimeSpan)value; var duration = timespan.Duration(); var timeSpanstring = string.Format("{0}{1} {2}:{3}:{4}.{5}", (timespan.Ticks < 0) ? "-" : "+", duration.Days.ToString().PadLeft(2, '0'), duration.Hours.ToString().PadLeft(2, '0'), duration.Minutes.ToString().PadLeft(2, '0'), duration.Seconds.ToString().PadLeft(2, '0'), duration.Milliseconds.ToString().PadLeft(6, '0')); NHibernateUtil.String.NullSafeSet(cmd, timeSpanstring, index); } public override Type ReturnedType { get { return typeof(TimeSpan); } } public override SqlType[] SqlTypes { get { return new[] { SqlTypeFactory.GetString(8) }; } } }  

编辑:添加了immutableUserType

 public abstract class ImmutableUserType : IUserType { public new virtual bool Equals(object x, object y) { return object.Equals(x, y); } public virtual int GetHashCode(object x) { return (x == null) ? 0 : x.GetHashCode(); } public override bool IsMutable { get { return false; } } public override object DeepCopy(object value) { return value; } public override object Replace(object original, object target, object owner) { return original; } public override object Assemble(object cached, object owner) { return cached; } public override object Disassemble(object value) { return value; } public abstract object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner); public abstract void NullSafeSet(System.Data.IDbCommand cmd, object value, int index); public abstract Type ReturnedType { get; } public abstract SqlType[] SqlTypes { get; } }