[*] Hello Snoopy

.NET and Flash Blog
Asp.Net Forums中对.Net中序列化和反序列化的应用

 

在Forums中,有些内容是不固定的,例如用户资料,除了一些基本资料,可能还要有一些其他资料信息,例如MSN、个人主页、签名档等,一般对于这样的都是每一个属性对应于数据库中的一个字段。但是如果以后我们因为需要增加一些属性,例如QQ号、Blog地址等,如果还是用这种增加数据表字段的方法,那么将会频繁的修改数据库表结构、存储过程、数据库访问的程序。

或许您也遇到过类似问题,看Forums中是怎么借用.Net的序列化和反序列化来解决的:
例如我需要在用户资料里面增加QQ号这个属性,那么我只需要在User类中增加一个属性
public String QQIM 
{
    get { return GetExtendedAttribute("QQIM"); }
    set { SetExtendedAttribute("QQIM", value); }
}
不需要修改数据库表结构,不需要修改存储过程,连数据库访问的程序都不需要动。

其具体实现的主要代码:

using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace console.UseSerialize
{
    
/// <summary>
    
/// ExtendedAttribute 的摘要说明。
    
/// </summary>

    public class ExtendedAttribute
    
{
        
public ExtendedAttribute()
        
{
            
//
            
// TODO: 在此处添加构造函数逻辑
            
//
        }

        
// 首先新建在User类中新建一个NameValueCollection对象,将这些扩展属性都保存在NameValueCollection对象中 
        private NameValueCollection extendedAttributes = new NameValueCollection(); 
 
        
/// <summary>
        
/// 从NameValueCollection集合中取纪录
        
/// </summary>
        
/// <param name="name">扩展属性名称</param>
        
/// <returns>返回扩展属性</returns>

        public string GetExtendedAttribute(string name)     
        

            
string returnValue = extendedAttributes[name]; 
 
            
if (returnValue == null
                
return string.Empty; 
            
else 
                
return returnValue; 
        }
 
 
        
/// <summary>
        
/// 设置扩展属性的在NameValueCollection中的键和值  
        
/// </summary>
        
/// <param name="name">扩展属性键</param>
        
/// <param name="value">扩展属性值</param>

        public void SetExtendedAttribute(string name, string value)     
        

            extendedAttributes[name] 
= value; 
        }
 
 
        
/// <summary>
        
/// 将extendedAttributes对象(前面定义的用来保存所有的用户扩展信息的NameValueCollection对象)
        
/// </summary>
        
/// <returns></returns>

        public byte[] SerializeExtendedAttributes()
        

            
// 序列化对象 
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            
// 创建一个内存流,序列化后保存在其中 
            MemoryStream ms = new MemoryStream(); 
            
byte[] b; 
            
// 将extendedAttributes对象(里面保存了所有的用户扩展信息)序列化为内存流 
            binaryFormatter.Serialize(ms, extendedAttributes); 
            
// 设置内存流的起始位置 
            ms.Position = 0
         
            
// 读入到 byte 数组 
            b = new Byte[ms.Length]; 
            ms.Read(b, 
0, b.Length); 
            ms.Close(); 
 
            
return b; 
        }
 
 
        
/// <summary>
        
/// 将二进制流,反序列化extendedAttributes对象的内容
        
/// </summary>
        
/// <param name="serializedExtendedAttributes">二进制流</param>

        public void DeserializeExtendedAttributes(byte[] serializedExtendedAttributes)  
        

            
if (serializedExtendedAttributes.Length == 0
                
return
            
try     
            

 
                BinaryFormatter binaryFormatter 
= new BinaryFormatter(); 
                MemoryStream ms 
= new MemoryStream(); 
 
                
// 将 byte 数组到内存流 
                ms.Write(serializedExtendedAttributes,0,serializedExtendedAttributes.Length); 
 
                
// 将内存流的位置到最开始位置 
                ms.Position = 0
 
                
// 反序列化成NameValueCollection对象,创建出与原对象完全相同的副本 
                extendedAttributes = (NameValueCollection) binaryFormatter.Deserialize(ms); 
 
                ms.Close(); 
            }
  
            
catch
            
{
            
            }
 
        }
 
    }

}

using System;
using System.Data;
using System.Data.SqlClient;

namespace console.UseSerialize
{
    
/// <summary>
    
/// test 的摘要说明。
    
/// </summary>

    public class test
    
{
        
public static void Main()
        
{
            
//伪码
            SqlConnection conn = new SqlConnection(@"connString");
            SqlCommand cmd 
= new SqlCommand(
                
@"SELECT NameValues FROM SomTable WHERE ID=1",conn);
            
            IDataReader reader 
= cmd.ExecuteReader(CommandBehavior.CloseConnection);

            ExtendedAttribute att 
= new ExtendedAttribute();
            
            
//从数据库中反序列化,并把读出的数据序列化到内存
            att.DeserializeExtendedAttributes((byte[])reader[0]);

            
//从内存中读取键值
            Console.WriteLine(att.GetExtendedAttribute("someName"));
            
            
//对数据修改后,重新序列化到内存,并保存到数据库
            
//一些修改
            att.SetExtendedAttribute("someName","y07070");
            
byte[] values = att.SerializeExtendedAttributes();

            
//数据库更新
            cmd.CommandText = @"UPDATE SET NameValues=@NameValues WHERE ID=1";
            cmd.Parameters.Add(
"@NameValues",SqlDbType.VarBinary,7000).Value = values;
            cmd.ExecuteNonQuery();
            
            conn.Close();

            Console.Read();
        }

    }

}


实质上序列化机制是将类的值转化为一个一般的(即连续的)字节流,然后就可以将该流保存到数据库的某个字段中(在数据库中forums_UserProfile表中有一个字段“StringNameValues varbinary(7500)”)。读取的过程对对象进行反序列化时,创建出与原对象完全相同的副本。

注意一般这类属性在数据库中是不能被检索到的,并且要这些属性能被序列化。

更详细内容请查阅MSDN和Asp.Net Forums源码
SRC:http://blog.joycode.com/dotey/archive/2004/12/10/40887.aspx

posted on 2005-01-27 15:43  HelloSnoopy  阅读(333)  评论(0)    收藏  举报