如果你希望能够在 ViewState 中保存 Self-Tracking Entities 对象,那么,将会遇到不能序列化的问题。
问题的原因在于 ViewState 通过将对象序列化之后通过隐藏域保存在网页中,所以,希望通过 ViewState 进行状态管理的对象必须支持序列化。
但是 Self-Tracking Entities 中生成的类没有序列化的标签,所以,导致使用失败。
幸运的是,Self-Tracking Entities 是通过 T4 - Text Template Transformation Toolkit 来生成代码的。
关于 T4 - Text Template Transformation Toolkit 可以参考我的另外一篇文章。VS2010 中的代码生成器 T4 - Text Template Transformation Toolkit
默认的 Self-Tracking Entities 模板中没有包含我们需要的标记说明来支持序列化,好消息就是我们可以简单的编辑一下 Self-Tracking Entities 的 T4 模板就可以了。
我们需要这几步就可以:
1. 增加 [Serializable] 标签到实体,复杂类型和集合类
2. 为字典集合类增加必须的序列化构造器
3. 为实体和复杂类型的 OnDerserializedMethod 方法增加一些代码,当一个实体被反序列化的时候来注册变化的跟踪事件
但是在 Silverlight 中还没有二进制的序列化。所以,如果你做了上面第1 和第 2 步的修改,那么,在 Silverlight 中将不能通过编译。
Self-Tracking Entities 在你的项目中加入了两个模板,其中一个用来生成 ObjectContext ,另外一个用来生成实体,我们需要修改的内容就在第二个用来生成实体的模板中。
第一件事就是给所有的类增加 [Serializable] 标签 以支持序列化。
先找到 37 行,增加 [Serializable] 后,应该如下所示:
38 < # = Accessibility.ForType(entity)# > < # = code.SpaceAfter(code.AbstractOption(entity))# > partial class < # = code.Escape(entity)# >< # = code.StringBefore( " : " , code.Escape(entity.BaseType))# >< # = entity.BaseType == null ? " : " : " , " # > IObjectWithChangeTracker, INotifyPropertyChanged
后面的修改依次如下。
1404 : public class TrackableCollection < T > : ObservableCollection < T >
1405 : {
1429 : public class ObjectChangeTracker
1430 : {
1651 : public class ObjectsAddedToCollectionProperties : Dictionary < string , ObjectList >
1652 { }
1656 : public class ObjectsRemovedFromCollectionProperties : Dictionary < string ,
ObjectList > { }
1661 : public class OriginalValuesDictionary : Dictionary < string , Object > { }
1666 : public class ExtendedPropertiesDictionary : Dictionary < string , Object > { }
1670 : public class ObjectList : List < object > { }
序列化构造器
下一步,我们要确认所有从 Dictionary<> 派生的类都完全支持序列化。
由于 Dictionary<> 类通过实现接口 ISerializable 来实现了自定义的序列化,所以,所有派生自 Dictionary<> 的类必须有一个特制的用于反序列化的构造函数。
并不需要我们为构造函数增加什么代码,仅仅需要有构造函数来支持 Dictionary<> 的反序列化。这里有四个类需要做修改。
ObjectsAddedToCollectionProperties 类
1652 : {
1653 : public ObjectsAddedToCollectionProperties() { }
1654 :
1655 : protected ObjectsAddedToCollectionProperties(SerializationInfo info,
1656 : StreamingContext ctx)
1657 : : base (info, ctx)
1658 : { }
1659 : }
ObjectsRemovedFromCollectionProperties 类
1665 : {
1666 : public ObjectsRemovedFromCollectionProperties() { }
1667 :
1668 : protected ObjectsRemovedFromCollectionProperties(SerializationInfo info,
1669 : StreamingContext ctx)
1670 : : base (info, ctx)
1671 : { }
1672 : }
OriginalValuesDictionary 类
1678 : {
1679 : public OriginalValuesDictionary() { }
1680 :
1681 : protected OriginalValuesDictionary(SerializationInfo info,
1682 : StreamingContext ctx)
1683 : : base (info, ctx)
1684 : { }
1685 : }
最后,ExtendedPropertiesDictionary 类
1691 : {
1692 : public ExtendedPropertiesDictionary() { }
1693 :
1694 : protected ExtendedPropertiesDictionary(SerializationInfo info,
1695 : StreamingContext ctx)
1696 : : base (info, ctx)
1697 : { }
1698 : }
事件的处理
由于在进行二进制序列化的时候不会序列化事件的处理,所以,在反序列化之后,我们可以通过 OnDeserialized 方法来执行一些我们自己的代码完成这个工作。
为了给实体增加这些工作,我们可以在模板中找到 OnDeserializedMethod 方法,然后增加三种重要的事件处理:
复杂类型事件处理
双向连接的集合属性的事件处理
级联删除的事件处理
将原来的 OnDeserializedMethod 方法直接用下面的替换掉
public void OnDeserializedMethod(StreamingContext context)
{
IsDeserializing = false ;
ChangeTracker.ChangeTrackingEnabled = true ;
< #
// Hook up ComplexType property event handlers
foreach (EdmProperty edmProperty in entity.Properties
.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity))
{
# >
if ( < # = code.FieldName(edmProperty)# > != null )
{
((INotifyComplexPropertyChanging) < # = code.FieldName(edmProperty)# > )
.ComplexPropertyChanging -= Handle < # = edmProperty.Name# > Changing;
((INotifyComplexPropertyChanging) < # = code.FieldName(edmProperty)# > )
.ComplexPropertyChanging += Handle < # = edmProperty.Name# > Changing;
}
< #
}
// Hook up Collection property event handlers
foreach (NavigationProperty navProperty in entity.NavigationProperties
.Where(np => np.DeclaringType == entity))
{
if (navProperty.ToEndMember.RelationshipMultiplicity ==
RelationshipMultiplicity.Many)
{
# >
if ( < # = code.FieldName(navProperty)# > != null )
{
< # = code.FieldName(navProperty)# > .CollectionChanged -= Fixup < # = navProperty.Name# > ;
< # = code.FieldName(navProperty)# > .CollectionChanged += Fixup < # = navProperty.Name# > ;
< #
if (ef.IsCascadeDeletePrincipal(navProperty))
{
# >
// This is the principal end in an association that performs cascade deletes.
// Add the cascade delete event handler for any entities that are
// already in the collection.
foreach (var item in < # = code.FieldName(navProperty)# > )
{
ChangeTracker.ObjectStateChanging -= item.HandleCascadeDelete;
ChangeTracker.ObjectStateChanging += item.HandleCascadeDelete;
}
< #
}
# >
}
< #
}
}
# >
}
完成上面的这些修改之后,你的 self-tracking entities 应该可以进行二进制序列化了,也就可以通过 ViewState 进行状态管理。
在 Jeff Derstadt 的文章 Using Binary Serialization and ViewState with Self-Tracking Entities 中,还给出了一个已经修改好的模版文件,这是链接地址:完成的模版
这篇文章来自:Jeff Derstadt 的文章,这是原文的链接:http://blogs.msdn.com/b/adonet/archive/2010/05/26/using-binary-serialization-and-viewstate-with-self-tracking-entities.aspx