代码之家  ›  专栏  ›  技术社区  ›  fostandy

持久化依赖于其他属性和自定义转换的属性

  •  0
  • fostandy  · 技术社区  · 15 年前

    我想知道如何持久化既依赖于常规持久化属性(例如string、int)又依赖于它们自己的一些自定义转换的属性。

    例如,假设我有

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

    根据某个特定的存储在数据库中的字符串[]来存储它。

    我的第一个想法是使用一个IUserType,但是这个方法NullSafeGet(IDataReader rs,string[]names,object owner)是在SomeString被持久化(或不持久)之前(或者实际上,在这个过程中)被调用的,所以没有设置它。

    我的第二个想法是使用ICompositeUserType和一些使用包装器的复杂设置。

    例如

    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)
        {
            // ...
        }
    
    }
    

    有人知道一种更简单、更简洁的方法吗?

    2 回复  |  直到 15 年前
        1
  •  0
  •   Spencer Ruport    15 年前

    我想做以下事情:

    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

        2
  •  0
  •   Community THelper    4 年前

    我离得那么远,却又那么近。当然,我们可以在NullSafeGet方法中从IDataReader访问dependent属性。

    完整的(-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)
            {
            // ...
            }
    
    
        }
    

    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)也会破坏这个实现。

      这是令人不快的,是的,但是必须直接在业务对象中存储持久性字段(和自定义序列化程序/反序列化程序包),并在每次获取/设置外部属性时调用这些字段。我认为,持久性验证应取用损坏的索引,并且此实现应导致一般来说,业务/持久性关注点的分离更为清晰。

    3. 把这个和(拉皮条客我的帖子?) sqlite's manifest typing capabilities 你还可以做一些非常酷的动态输入功能:)