2011-05-27 33 views
4

我使用NHibernate和Postgresql作爲後端,並且必須創建自定義類型來將System.DateTime轉換爲Postgresql「time」類型以及將System.TimeSpans轉換爲「interval」db類型。我創建的IUserType正在工作,正在應用於讀取和更新,但是當我嘗試將對象插入數據庫時​​,它們從未應用。我在IUserTypes中設置了斷點,但是當插入發生時它們從未被擊中。NHibernate IUserType不適用於插入

我認爲這個問題可能是因爲對象只是一個POCO對象,而不是一個代理,所以當我設置我的屬性的值時不會發生將轉換應用到usertype的映射。

如果我進行更新並設置其中一個屬性,我可以看到IUserType中的斷點被觸發。

有什麼想法?

UPDATE IUserType的Equals方法被調用,但我做必要的轉換的NullSafeSet不是。

編輯 添加的代碼樣本

public class TimeType : BaseImmutableUserType<TimeSpan> 
    { 
     public override object NullSafeGet(IDataReader rs, string[] names, object owner) 
     { 
      var val = NHibernateUtil.Time.NullSafeGet(rs, names[0]); 
      if (val == null) 
       return null; 

      var dt = DateTime.Parse(val.ToString()); 

      return new TimeSpan(0, dt.Hour, dt.Minute, dt.Second); 
     } 

     public override void NullSafeSet(IDbCommand cmd, object value, int index) 
     { 
      var obj = (TimeSpan)value; 

      ((IDbDataParameter) cmd.Parameters[index]).Value = obj; 
     } 

     public override SqlType[] SqlTypes 
     { 
      get 
      { 
       return new[] { SqlTypeFactory.Time }; 
      } 
     } 
    } 

    public abstract class BaseImmutableUserType<T> : IUserType 
    { 
     public abstract object NullSafeGet(IDataReader rs, string[] names, object owner); 
     public abstract void NullSafeSet(IDbCommand cmd, object value, int index); 
     public abstract SqlType[] SqlTypes { get; } 

     public BaseImmutableUserType() 
     { 
      int i = 0; 
     } 

     public new bool Equals(object x, object y) 
     { 
      if (ReferenceEquals(x, y)) 
      { 
       return true; 
      } 

      if (x == null || y == null) 
      { 
       return false; 
      } 

      return x.Equals(y); 
     } 

     public int GetHashCode(object x) 
     { 
      return x.GetHashCode(); 
     } 

     public object DeepCopy(object value) 
     { 
      return value; 
     } 

     public object Replace(object original, object target, object owner) 
     { 
      return original; 
     } 

     public object Assemble(object cached, object owner) 
     { 
      return DeepCopy(cached); 
     } 

     public object Disassemble(object value) 
     { 
      return DeepCopy(value); 
     } 

     public Type ReturnedType 
     { 
      get { return typeof(T); } 
     } 

     public bool IsMutable 
     { 
      get { return false; } 
     } 
} 
+0

我不得不做的一樣Sybase DB和它工作正常。你可以發佈你的UserType類嗎?我的猜測是那裏有一個錯誤。您的域類中的屬性具有DateTime作爲其類型,對嗎? – 2011-05-28 20:00:07

+0

僅當執行查詢之前設置的參數值時才調用NullSafeSet。你可以發佈一些代碼嗎? – Phill 2011-06-03 06:03:26

+0

@Florian Lim我查看了Npgsql的源代碼,它看起來不像System.DateTime和db類型的'time'之間有明確的轉換。我一直在使用System.TimeSpans,它們正確地工作更新和讀取只是不插入。 – 2011-06-03 15:08:51

回答

2

我發現下面的兩個選項:

選項1:不要使用自己的用戶類型。而是使用NHibernate的自己TimeAsTimeSpan這樣的:(從here採取例)

Map(x => x.TimeFrom) 
    .CustomType("TimeAsTimeSpan"); 

選項2:修改類一點:

public class TimeType : BaseImmutableUserType<TimeSpan> 
{ 
    // this is taken from the source of NHibernate.Type.TimeAsTimeSpanType 
    private static readonly DateTime BaseDateValue = new DateTime(1753, 01, 01); 

    public override object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     var val = NHibernateUtil.TimeAsTimeSpan.NullSafeGet(rs, names[0]); 
     if (val == null) 
      return null; 

     var dt = DateTime.Parse(val.ToString()); 

     return new TimeSpan(0, dt.Hour, dt.Minute, dt.Second); 
    } 

    public override void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     //var obj = (TimeSpan)value; // we can't use TimeSpan here but need to use DateTime 
     // this is taken from the source of NHibernate.Type.TimeAsTimeSpanType 
     DateTime date = BaseDateValue.AddTicks(((TimeSpan)value).Ticks); 
     ((IDbDataParameter)cmd.Parameters[index]).Value = date; 
    } 

    public override SqlType[] SqlTypes 
    { 
     get 
     { 
      return new[] { NHibernate.SqlTypes.SqlTypeFactory.Time }; 
     } 
    } 
}