通过 ViewState 保存 SelfTracking Entities

如果你希望能够在 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] 后,应该如下所示:

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
 

 后面的修改依次如下。

1403: [Serializable]
1404public class TrackableCollection<T> : ObservableCollection<T>
1405: {
1428: [Serializable]
1429public class ObjectChangeTracker
1430: {
1650: [Serializable]
1651public class ObjectsAddedToCollectionProperties : Dictionary<string, ObjectList>
1652  { }
1655: [Serializable]
1656public class ObjectsRemovedFromCollectionProperties : Dictionary<string,
       ObjectList> { }

1660: [Serializable]
1661public class OriginalValuesDictionary : Dictionary<string, Object> { }

1665: [Serializable]
1666public class ExtendedPropertiesDictionary : Dictionary<string, Object> { }
1669: [Serializable]
1670public class ObjectList : List<object> { }

序列化构造器

下一步,我们要确认所有从 Dictionary<> 派生的类都完全支持序列化。

由于 Dictionary<> 类通过实现接口  ISerializable 来实现了自定义的序列化,所以,所有派生自 Dictionary<> 的类必须有一个特制的用于反序列化的构造函数。

并不需要我们为构造函数增加什么代码,仅仅需要有构造函数来支持  Dictionary<>  的反序列化。这里有四个类需要做修改。

ObjectsAddedToCollectionProperties

 1651public class ObjectsAddedToCollectionProperties : Dictionary<string, ObjectList>
 1652: {
 1653:     public ObjectsAddedToCollectionProperties() { }
 1654:
 1655:     protected ObjectsAddedToCollectionProperties(SerializationInfo info,
 1656:                                                  StreamingContext ctx) 
 1657:         : base(info, ctx)
 1658:     { }
 1659: }

ObjectsRemovedFromCollectionProperties 类

 1664public class ObjectsRemovedFromCollectionProperties : Dictionary<stringObjectList>
 1665: {
 1666:     public ObjectsRemovedFromCollectionProperties() { }
 1667:
 1668:     protected ObjectsRemovedFromCollectionProperties(SerializationInfo info, 
 1669:                                                      StreamingContext ctx) 
 1670:        : base(info, ctx)
 1671:    { }
 1672: }

OriginalValuesDictionary

 1677public class OriginalValuesDictionary : Dictionary<string, Object>
 1678: {
 1679:     public OriginalValuesDictionary() { }
 1680:
 1681:     protected OriginalValuesDictionary(SerializationInfo info,
 1682:                                        StreamingContext ctx) 
 1683:         : base(info, ctx)
 1684:     { }
 1685: }

最后,ExtendedPropertiesDictionary 类

 1690public class ExtendedPropertiesDictionary : Dictionary<string, Object>
 1691: {
 1692:     public ExtendedPropertiesDictionary() { }
 1693:
 1694:     protected ExtendedPropertiesDictionary(SerializationInfo info, 
 1695:                                            StreamingContext ctx) 
 1696:         : base(info, ctx)
 1697:     { }
 1698: }

事件的处理

由于在进行二进制序列化的时候不会序列化事件的处理,所以,在反序列化之后,我们可以通过 OnDeserialized  方法来执行一些我们自己的代码完成这个工作。

为了给实体增加这些工作,我们可以在模板中找到 OnDeserializedMethod  方法,然后增加三种重要的事件处理:

复杂类型事件处理

双向连接的集合属性的事件处理

级联删除的事件处理

将原来的 OnDeserializedMethod 方法直接用下面的替换掉

[OnDeserialized]
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

原文地址:https://www.cnblogs.com/haogj/p/1757449.html