通过 ViewState 保存 Self-Tracking 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]
1404 public   class  TrackableCollection < T >  : ObservableCollection < T >
1405 : {

 

1428 : [Serializable]
1429 public   class  ObjectChangeTracker
1430 : {

 

1650 : [Serializable]
1651 public   class  ObjectsAddedToCollectionProperties : Dictionary < string , ObjectList >
1652   { }

 

1655 : [Serializable]
1656 public   class  ObjectsRemovedFromCollectionProperties : Dictionary < string ,
        ObjectList >  { }

 

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

 

1665 : [Serializable]
1666 public   class  ExtendedPropertiesDictionary : Dictionary < string , Object >  { }

 

1669 : [Serializable]
1670 public   class  ObjectList : List < object >  { }

 

序列化构造器

 

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

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

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

ObjectsAddedToCollectionProperties

 1651 public   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 类

 

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

OriginalValuesDictionary

 1677 public   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 类

 1690 public   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

 

你可能感兴趣的:(rack)