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