CommunityServer 的对象持久化

      CommunityServer中广泛应用了一种对象持久化的机制,  这种机制和.Net2.0中的Profile是相同的原理,把对象序列化为一个字符串保存到数据库的一个字段中,同时使用另一个字段保存对象所在字符串的位置,看看一个例子:

[PropertyNames]字段的值:
EnableAllPreview:S: 0 : 5 :EnablePreviewResumeAttachment:S: 5 : 4 :EnablePreviewBaseInfo:S: 9 : 4 :EnablePreviewDetailInfo:S: 13 : 4 :EnablePreviewJobExp:S: 17 : 5 :EnablePreviewEduExp:S: 22 : 5 :EnablePreviewUserSkill:S: 27 : 5 :EnablePreviewUserLanguage:S: 32 : 5 :EnablePreviewCertificate:S: 37 : 5 :EnablePreviewAdvUser:S: 42 : 5 :EnablePreviewTrainingExperience:S: 47 : 5 :EnablePreviewProjectExperience:S: 52 : 5 :
[PropertyValues]字段的值:
FalseTrueTrueTrueFalseFalseFalseFalseFalseFalseFalseFalse
上面代码中的"S:0:5"表示了对象在字符串中的位置和类型
"S"表示这个对象是一个字符串
"0"表示这个对象在字符串中开始的索引
"5"表示这个对象的长度
根据这些信息,程序或都SQL代码都可以提取出所需要的对象,例如:
EnableAllPreview:S:0:5: 表示EnableAllPreview表示这个对象保存在[PropertyValues]中是一个字符串的形式,并且它的开始位置是从0开始,长度为5个字符,根据这样的条件可以得到对象的值是False

      CommunityServer内部已经封装好了一些方法用于方便使用这样的持久化机制.

1.为想使用这种持久化机制的表添加两个字段:
ALTER   TABLE  Job_ResumeState  ADD  PropertyNames  ntext   NULL
ALTER   TABLE  Job_ResumeState  ADD  PropertyValues  ntext   NULL

2.表对应的对象继承于ExtendedAttributes对象,对象中封装了一些方法,让你可以非常方便的添加扩展属性.
[Serializable]
    
public   class  ExtendedAttributes
    {
        
public  ExtendedAttributes() { }

        NameValueCollection extendedAttributes 
=   new  NameValueCollection();

        
/// <summary>
        
///  获取扩展属性
        
///   </summary>
         public   string  GetExtendedAttribute( string  name)
        {
            
string  returnValue  =  extendedAttributes[name];

            
if  (returnValue  ==   null )
                
return   string .Empty;
            
else
                
return  returnValue;
        }

        
/// <summary>
        
///  设置扩展属性
        
///   </summary>
         public   void  SetExtendedAttribute( string  name,  string  value)
        {
            
if  ((value  ==   null ||  (value  ==   string .Empty))
                extendedAttributes.Remove(name);
            
else
                extendedAttributes[name] 
=  value;
        }

        
/// <summary>
        
///  扩展属性的数量
        
///   </summary>
         public   int  ExtendedAttributesCount
        {
            
get  {  return  extendedAttributes.Count; }
        }

        
/// <summary>
        
///  获取Bool型的扩展属性
        
///   </summary>
         public   bool  GetBool( string  name,  bool  defaultValue)
        {
            
string  b  =  GetExtendedAttribute(name);
            
if  (b  ==   null   ||  b.Trim().Length  ==   0 )
                
return  defaultValue;
            
try
            {
                
return   bool .Parse(b);
            }
            
catch  { }
            
return  defaultValue;
        }

        
/// <summary>
        
///  获取整型扩展属性
        
///   </summary>
         public   int  GetInt( string  name,  int  defaultValue)
        {
            
string  i  =  GetExtendedAttribute(name);
            
if  (i  ==   null   ||  i.Trim().Length  ==   0 )
                
return  defaultValue;

            
return  Int32.Parse(i);
        }

        
/// <summary>
        
///  获取日期型扩展属性
        
///   </summary>
         public  DateTime GetDateTime( string  name, DateTime defaultValue)
        {
            
string  d  =  GetExtendedAttribute(name);
            
if  (d  ==   null   ||  d.Trim().Length  ==   0 )
                
return  defaultValue;

            
return  DateTime.Parse(d);
        }

        
/// <summary>
        
///  获取字符型扩展属性
        
///   </summary>
         public   string  GetString( string  name,  string  defaultValue)
        {
            
string  v  =  GetExtendedAttribute(name);
            
return  (String.IsNullOrEmpty(v))  ?  defaultValue : v;
        }

        Serialization
#region  Serialization

        
/// <summary>
        
///  获取扩属性的序列化数据
        
///   </summary>
        
///   <returns></returns>
         public  SerializerData GetSerializerData()
        {
            SerializerData data 
=   new  SerializerData();
            
// data.Bytes = Serializer.ConvertToBytes(this.extendedAttributes);

            
string  keys  =   null ;
            
string  values  =   null ;

            Serializer.ConvertFromNameValueCollection(
this .extendedAttributes,  ref  keys,  ref  values);
            data.Keys 
=  keys;
            data.Values 
=  values;

            
return  data;
        }

        
/// <summary>
        
///  设置扩属性的序列化数据
        
///   </summary>
         public   void  SetSerializerData(SerializerData data)
        {
            
//             if(data.Bytes != null)
            
//             {
            
//                 try
            
//                 {
            
//                     extendedAttributes = Serializer.ConvertToObject(data.Bytes) as NameValueCollection;
            
//                 }
            
//                 catch{}
            
//             }

            
if  ( this .extendedAttributes  ==   null   ||   this .extendedAttributes.Count  ==   0 )
            {
                
this .extendedAttributes  =  Serializer.ConvertToNameValueCollection(data.Keys, data.Values);
            }

            
if  ( this .extendedAttributes  ==   null )
                extendedAttributes 
=   new  NameValueCollection();
        }
        
#endregion

    }

其中的public SerializerData GetSerializerData()和public void SetSerializerData(SerializerData data)用于获取和添加序列化数据时使用,在下面的例子中会有更详细的讨论,而其它方法都是为了方便从序列化中获取或者设置对象的助手方法.
看一下继承于此扩展属性类的类:
  [Serializable]
    
public   class  ResumeState : ExtendedAttributes
    {
        
private  Guid resumeid;
        
public  Guid Resumeid
        {
            
get  {  return  resumeid; }
            
set  { resumeid  =  value; }
        }
        
public   bool  EnableAllPreview
        {
            
get  {  return  GetBool( " EnableAllPreview " false ); }
            
set  { SetExtendedAttribute( " EnableAllPreview " , value.ToString()); }
        }
        
public   bool  EnablePreviewBaseInfo
        {
            
get  {  return  GetBool( " EnablePreviewBaseInfo " false ); }
            
set  { SetExtendedAttribute( " EnablePreviewBaseInfo " , value.ToString()); }
        }

    }
其中的EnableAllPreview和EnablePreviewBaseInfo属性就是一个扩展属性,这属性是使用序列化的机制进行保存的,它伴随着对象进行获取,添加,更新,删除,只要框架定好了添加一个新的扩展属性并不需要任何数据库操作就能够快速的实现.

3.扩展属性是如何加载到对象的,这里看一段代码从数据库返回的IDataReader填充对象的操作:
      public   static  ResumeState PopulateResumeStateFromIDataReader(IDataReader dr)
        {
            ResumeState state 
=   new  ResumeState();
            SerializerData data 
=   new  SerializerData(); 

            state.Resumeid 
=  (Guid)dr[ " Resumeid " ];
            state.ViewType 
=  (ViewType)dr[ " ViewType " ];

            data.Keys 
=  ProviderHelper.GetString(dr,  " PropertyNames " null );
            data.Values 
=  ProviderHelper.GetString(dr,  " PropertyValues " null );

            state.SetSerializerData(data);
              
            
return  state;
        }
SerializerData data = new SerializerData(); 是用来保存对象名值对的自定义对象
   public   class  SerializerData
    {
        
public   string  Keys;
        
public   string  Values;
    }
事实上对象的提取就是根据键值进行提取的,这个对象会在state.SetSerializerData(data);方法中填充并反序列化到一个NameValueCollection对象中,这个对象就是保存在ExtendedAttributes类中的NameValueCollection extendedAttributes
有了这个NameValueCollection后就可以根据键来得到其相应的值,例如:
get { return GetBool("EnableAllPreview", false); }就可以获取EnableAllPreview属性的值

4.扩展属性如何保存到数据库字段中?
public   override   int  InsertResumeState(ResumeState resumeState)
        {
            Database db 
=  DatabaseFactory.CreateDatabase();

            SerializerData data 
=  resumeState.GetSerializerData();

            
string  sqlCommand  =   " Job_ResumeState_Insert " ;
            DbCommand dbCommand 
=  db.GetStoredProcCommand(sqlCommand);
            db.AddInParameter(dbCommand, 
" @Resumeid " , DbType.Guid, resumeState.Resumeid);
            db.AddInParameter(dbCommand, 
" @ViewType " , DbType.Int32, resumeState.ViewType);
            db.AddInParameter(dbCommand, 
" @PropertyNames " , DbType.String, data.Keys);
            db.AddInParameter(dbCommand, 
" @PropertyValues " , DbType.String, data.Values);
            db.AddOutParameter(dbCommand, 
" @retvar " , DbType.Int32,  4 );

            
try
            {
                db.ExecuteNonQuery(dbCommand);
                
return  ( int )db.GetParameterValue(dbCommand,  " @retvar " );
            }
            
catch
            {
                
return   - 1 ;
            }
        }

如上例子,在添加一新简历状态时只需要使用封装好的方法获取当前对象的扩展属性的SerializerData对象
SerializerData data = resumeState.GetSerializerData();
因为ResumeState是继承于ExtendedAttributes属性的,所以可以直接使用GetSerializerData()方法序列化出一个含有扩展属性的序列化字符串,从而可以保存到数据库:
db.AddInParameter(dbCommand,  " @PropertyNames " , DbType.String, data.Keys);
            db.AddInParameter(dbCommand, 
" @PropertyValues " , DbType.String, data.Values);
最后贴上一个封装好的序列化和反序化方法:
///   <summary>
        
///  Creates a NameValueCollection from two string. The first contains the key pattern and the second contains the values
        
///  spaced according to the kys
        
///   </summary>
        
///   <param name="keys"> Keys for the namevalue collection </param>
        
///   <param name="values"> Values for the namevalue collection </param>
        
///   <returns> A NVC populated based on the keys and vaules </returns>
        
///   <example>
        
///  string keys = "key1:S:0:3:key2:S:3:2:";
        
///  string values = "12345";
        
///  This would result in a NameValueCollection with two keys (Key1 and Key2) with the values 123 and 45
        
///   </example>
         public   static  NameValueCollection ConvertToNameValueCollection( string  keys,  string  values)
        {
            NameValueCollection nvc 
=   new  NameValueCollection();

            
if  (keys  !=   null   &&  values  !=   null   &&  keys.Length  >   0   &&  values.Length  >   0 )
            {
                
char [] splitter  =   new   char [ 1 ] {  ' : '  };
                
string [] keyNames  =  keys.Split(splitter);

                
for  ( int  i  =   0 ; i  <  (keyNames.Length  /   4 ); i ++ )
                {
                    
int  start  =   int .Parse(keyNames[(i  *   4 +   2 ], CultureInfo.InvariantCulture);
                    
int  len  =   int .Parse(keyNames[(i  *   4 +   3 ], CultureInfo.InvariantCulture);
                    
string  key  =  keyNames[i  *   4 ];

                    
// Future version will support more complex types    
                     if  (((keyNames[(i  *   4 +   1 ==   " S " &&  (start  >=   0 ))  &&  (len  >   0 &&  (values.Length  >=  (start  +  len)))
                    {
                        nvc[key] 
=  values.Substring(start, len);
                    }
                }
            }

            
return  nvc;
        }

        
/// <summary>
        
///  Creates a the keys and values strings for the simple serialization based on a NameValueCollection
        
///   </summary>
        
///   <param name="nvc"> NameValueCollection to convert </param>
        
///   <param name="keys"> the ref string will contain the keys based on the key format </param>
        
///   <param name="values"> the ref string will contain all the values of the namevaluecollection </param>
         public   static   void  ConvertFromNameValueCollection(NameValueCollection nvc,  ref   string  keys,  ref   string  values)
        {
            
if  (nvc  ==   null   ||  nvc.Count  ==   0 )
                
return ;

            StringBuilder sbKey 
=   new  StringBuilder();
            StringBuilder sbValue 
=   new  StringBuilder();

            
int  index  =   0 ;
            
foreach  ( string  key  in  nvc.AllKeys)
            {
                
if  (key.IndexOf( ' : ' !=   - 1 )
                    
throw   new  ArgumentException( " ExtendedAttributes Key can not contain the character \ " :\ "" );

                
string  v  =  nvc[key];
                
if  ( ! String.IsNullOrEmpty(v))
                {
                    sbKey.AppendFormat(
" {0}:S:{1}:{2}: " , key, index, v.Length);
                    sbValue.Append(v);
                    index 
+=  v.Length;
                }
            }
            keys 
=  sbKey.ToString();
            values 
=  sbValue.ToString();
        }

你可能感兴趣的:(server)