如果你希望能够在 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