2009-07-31 60 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,你可以做一些非常酷的动态类型的东西:)