2009-07-31 35 views
0

我想知道如何保持一個屬性,這取決於常規持久屬性(例如,字符串,int)以及一些自定義轉換。堅持依賴其他屬性和自定義轉換的屬性

例如假設我有

class A 
{ 
    public int Id {get; set;} 
    public string SomeString {get; set;} 
    public object SpecialProperty {get; set;} 
} 

假設持續SpecialProperty需要讀取SomeString並且取決於它的值,從而產生一些字節[]然後可將其存儲在數據庫中。我的第一個想法是使用一個IUserType,但是這個方法NullSafeGet(IDataReader rs,string [] names,object owner)在(或實際上,在)SomeString被持久化(或不)時被調用,所以它是沒有設置。

我的第二個想法是使用ICompositeUserType和一些使用包裝器的相當複雜的設置。

我的第三個想法可能是我可以實現ILifecycle並掛鉤OnLoad()方法。但如果我想這樣做,我將需要爲byte []有效載荷創建一個獨立的屬性,我不想存儲它。這當然似乎是最容易實現的,但也有點不雅觀。

例如

class A : ILifecycle 
{ 
    public int Id {get; set;} 
    public string SomeString {get; set;} 
    public object SpecialProperty {get; set;} 

    private byte[] payloadData { get; set; } 

    public void OnLoad(ISession s, object id) 
    { 
     SpecialProperty = customIn(SomeString, payloadData); 
     payloadData = null; 

    } 

    static object customIn(string a, byte[] payload) 
    { 
     // ... 
    } 

} 

有沒有人知道一個更容易和可能更簡潔的方式?

回答

0

我會做類似如下:

class A 
{ 
    public virtual int Id {get; set;} 
    protected virtual string _SomeString { get; set; } 
    protected virtual object _SpecialProperty { get; set; } 

    public virtual object SpecialProperty {get { return _SpecialProperty; } } 
    public virtual string SomeString {get { return _SomeString; } set { _SomeString = value; _SpecialProperty = SomeManipulatorMethod(value); } } 
} 

我只映射Id_SomeString_SpecialProperty

0

我到目前爲止還很近。當然,事實證明,我們可以從NullSafeGet方法中的IDataReader訪問依賴屬性。

完整(-ish)解決方案是在這裏:

首先讓我們來定義一個流利的映射:

public class AMap : ClassMap<A> 
    { 
     public AMap() 
     { 
      Id(x => x.Id); 
      Map(x => x.SomeString); 
      Map(x => x.SpecialProperty) 
       .CustomType(typeof (DependentProperty)) 
       ; 
     } 

     static object DeserialiseSpecialProperty(string SomeString, byte[] specialProperty) 
     { 
     // ... 
     } 

     static byte[] SerialiseSpecialProperty(object specialProperty) 
     { 
     // ... 
     } 


    } 

現在,實現DependentProperty。

public class DependentProperty: IUserType 
{ 
// change SqlTypes appropriatelly if your backing field is something else 
    public SqlType[] SqlTypes { get { return new[] {new SqlType(DbType.Binary)}; } } 

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

    public bool IsMutable { get { return false; } } 

    public int GetHashCode(object x) 
    { 
     if (x == null) 
      return 0; 
     return x.GetHashCode(); 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     var SomeString = (string)rs.GetValue(1); 
     object obj = NHibernateUtil.Binary.NullSafeGet(rs, names[0]); 
     return AMap.DeserialiseSpecialProperty(SomeString, (byte[])obj); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     if (value == null) 
      ((IDataParameter) cmd.Parameters[index]).Value = DBNull.Value; 
     else 
      ((IDataParameter)cmd.Parameters[index]).Value = AMap.DeserialiseSpecialProperty(value); 
    } 

    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 cached; } 

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

    bool IUserType.Equals(object x, object y) { return object.Equals(x, y); } 
} 

注:

  1. 的IUserType實現是基於模板從a nhibernate.info tutorial。對於值類型應該沒問題,但如果您正在做任何與參考類型或深度對象圖形複雜的事情,則可能需要爲各種方法提供不同的實現。

  2. 由於直接訪問IDataReader這是非常脆弱。對AMap中映射順序的更改很可能會要求您更新訪問的索引。很可能AMap(甚至可能是A)的其他變化也可能會破壞這個實現。

    這是令人不愉快的,但是這樣的話,必須將持久性字段(以及自定義序列化程序/反序列化程序包)直接存儲在業務對象中,並且每次外部屬性被get/set'd時都會調用它們。我會爭辯說,應該通過持久性驗證來挑選一個破損的索引,並且這個實現應該導致商業/持久性問題的分離更加清晰。

  3. 與此相結合(皮條客我的帖子?)sqlite's manifest typing capabilities,你可以做一些非常酷的動態類型的東西:)