2011-09-15 49 views
4

與我向我的一位同事挑戰的問題不是一個問題,而是昨天由DBA提出的。我們有一個TimeSpan財產在我們的對象之一,必須堅持。是的,您可以只從對象的開始和結束DateTime屬性推斷值,但DBA堅持將此值保存在數據庫表中。NHibernate映射爲Oracle INTERVAL DAY TO SECOND數據類型

因此,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') 
       ); 
      } 
     } 
    } 

隨着映射爲

<property name="TimeSpanTest" column="TIMESPAN_TEST"/> 

一個非常諾迪測試作爲

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」。如果值爲負,則A-符號在字符串的開頭也是有效的。這裏需要注意的一個重點是:當值爲負值時,TimeSpan對象的每個部分在單獨查看時都是負數,因此不是那麼漂亮的「value.Days.ToString()。Contains(' - ')」in Format()方法的每個部分。

我們的測試通過,我們能夠通過NHibernate將TimeSpan值保存並檢索到數據庫列中定義爲INTERVAL DAY(2)TO SECOND(6)。

如果有人以更好的方式做到這一點,我會非常感興趣知道如何。

道歉不鏈接Oracle類型,這是我的第一篇文章,所以我不允許...

+0

你也可以去用NH- Usertype映射Timespan屬性。那麼你不需要TimeSpanTest和對象中的轉換代碼。如果需要,我可以發佈實施 – Firo

+0

請。就像我說的,這是我們的第一個解決方案,如果有更好的方法,我想知道如何去做。 –

回答

2
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) }; } 
    } 
} 

<property name="ActualTimeSpan" column="TIMESPAN_TEST" type="TimeSpanUserType"/> 

編輯:添加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; } 
} 
+0

感謝您的回覆。我不知道你如何使用IDataReader和IDbCommand與NHibernate接口。 –

+0

我不明白這個問題。就像NH代碼給出的參數一樣,你只需插入/檢索值 – Firo

+1

謝謝@Firo它爲我工作 – saggu