SPB-设计机制-序列化字段
导航: 上一页
在产品的不断完善过程中或者二次开发过程中,经常需要对现有的对象增加新的属性。通常情况下,为了应对这些变化需要在数据库的相应表中预留字段(当然不预留字段就需要修改数据库中的表、修改相应的存储过程或sql语句、修改数据访问层…),然后在使用时赋予具体的含义。
这样做最常见的一个结果就是使数据库中的一些字段异常混乱。
在SpaceBuilder中,我们针对这种需求使用了序列化字段,下面介绍数据序列化的原理及如何使用数据序列化。
一、数据库的存储格式
在数据库中的存储格式如下图所示,所有需要序列化的数据全部存储到PropertyNames(存储属性名称及PropertyValues中对应的存储位置)、PropertyValues(存储属性的具体数据)两个字段中。
先分析一下存储的数据,首先是PropertyNames字段 “EnableRatings:S:0:4:EnableTrackBacks:S:4:4:CommentModerationType:S:8:4:” ,“EnableRatings”其实是在实体类中定义的一个属性名称,“:”表示定义完毕,“S:0:4”表示在PropertyValues字段中的字符从0开始后面4位属于“EnableRatings”的属性值,同理:“S:4:4”表示,从第四个字符开始,后面5个表示“EnableTrackBacks”的属性值,依次类推可以获得PropertyNames所有的字段的值。(其中S代表存储格式是字符串,由于目前全部以字符串存储所以不需特别关注)。
这样我们就利用PropertyNames、PropertyValues两个字段存储任意多个数据项,而且不用对操作数据库的存储过程或sql语句做任何更改,这就为SpaceBuilder的数据序列化奠定了数据存储基础。
设计参考:
借鉴了asp.net 2.0的Profile。Profile的功能是管理用户个人资料,而用户个人资料在不同的项目中会有不同的需求(比如:年龄、性别、兴趣、爱好、毕业院校…),而Profile作为一个通用的功能必须满足这些具体的需求,它同样采取了类似的数据存储结构,如下图所示。
Profile采用了3个字段对扩展属性进行存储:
- PropertyNames同样存储属性名称及在PropertyValuesString或PropertyValuesBinary中的相应数据的存储位置,并以S及B确定数据是以字符串形式还是二进制形式存储;
- PropertyValuesString存储属性的字符串数据;
- PropertyValuesBinary存储属性的二进制数据;
当然Profile为了做到更加容易对Profile扩展新的属性,还支持在web.config中通过配置文件来增加新属性。
二、如何使用数列化数据
- 首先确保需要使用序列化字段的实体类从SpaceBuilder.Common.ExtendedAttributes派生。
例如:User,如下图所示:
ExtendedAttributes主要方法如下:
在ExtendedAttributes的派生类我们可以方便的通过GetBool、GetInt、GetDouble、GetString、GetExtendedAttribute<T>获取相应的属性值。GetSerializerData、SetSerializerData一般用于把对象存储到数据库,或从数据库取出数据并生成对象的过程使用(参见2)。
例如,我们可以定义AvatarUrl序列化属性,该属性的代码如下:
/// <summary> /// 用户头像文件名称 /// </summary> public string AvatarUrl { get { return GetExtendedAttribute("avatarUrl"); } set { SetExtendedAttribute("avatarUrl", value); }
}
- 在数据库的表中增加PropertyNames、PropertyValues两个字段,一般设置PropertyNames、PropertyValues的类型为ntext。
进行对象持久化时(即存储到数据库),需要编写如下代码:
SerializerData data = user.GetSerializerData(); myCommand.Parameters.Add("@PropertyNames", SqlDbType.NText).Value = data.Keys; myCommand.Parameters.Add("@PropertyValues", SqlDbType.NText).Value = data.Values;
从数据库取出数据生成对象时,一般需要编写如下代码:
SerializerData data = new SerializerData(); if (dr["PropertyNames"] == DBNull.Value) data.Keys = ""; else data.Keys = dr["PropertyNames"] as string; if (dr["PropertyValues"] == DBNull.Value) data.Values = ""; else data.Values = dr["PropertyValues"] as string; user.SetSerializerData(data);