正如 Headers 所说,我在序列化自动生成的POCO对象时遇到了一些问题 . 但首先是一些背景信息:
我已按照本指南使用EF 4.0和ADO.Net POCO实体生成器创建了数据访问层:http://blogs.msdn.com/b/adonet/archive/2010/01/25/walkthrough-poco-template-for-the-entity-framework.aspx .
我现在有2个类库,一个使用EF模型,第二个使用T4自动生成的POCO实体 .
目前我正在开发另一个项目,我想使用我的DAL类库 . 我必须检索一些对象并将它们序列化为XML . 首先我尝试了XmlSerializer,但后来我发现它有圆周参考的问题 . 我使用XmlIgnore修复了这个问题,但后来我遇到序列化问题:
Public Overridable Property NwlGroup As ICollection(Of NwlGroup)
因为XmlSerializer不支持接口 .
其次,我在自动生成的实体Poco类文件中尝试了DataContractSerializer和[DataContract]和[DataMember]属性 . 这工作,但自然我不得不清理自动生成的文件中的更改,因此我想使用MetaDataType属性 . 我创建了这样的额外文件:
Imports System.Runtime.Serialization
Imports System.ComponentModel.DataAnnotations
<MetadataType(GetType(NewsletterCustomerMetadata))>
Partial Public Class NewsletterCustomer
End Class
<DataContract()
Public Class NewsletterCustomerMetadata
<DataMember(Name:="emailaddress", IsRequired:=True)>
Public Overridable Property Emailaddress As String
<DataMember(Name:="name")>
Public Overridable Property Name As String
<DataMember()>
Public Overridable Property NwlGroup As ICollection(Of NwlGroup)
End Class
自动生成的文件:
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated from a template.
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports System.Runtime.Serialization
Public Class NewsletterCustomer
#Region "Primitive Properties"
Public Overridable Property ID As Integer
Public Overridable Property Emailaddress As String
Public Overridable Property Name As String
...
#Region "Navigation Properties"
Public Overridable Property NwlGroup As ICollection(Of NwlGroup)
Get
If _nwlGroup Is Nothing Then
Dim newCollection As New FixupCollection(Of NwlGroup)
AddHandler newCollection.CollectionChanged, AddressOf FixupNwlGroup
_nwlGroup = newCollection
End If
Return _nwlGroup
End Get
Set(ByVal value As ICollection(Of NwlGroup))
If _nwlGroup IsNot value Then
Dim previousValue As FixupCollection(Of NwlGroup) = TryCast(_nwlGroup, FixupCollection(Of NwlGroup))
If previousValue IsNot Nothing Then
RemoveHandler previousValue.CollectionChanged, AddressOf FixupNwlGroup
End If
_nwlGroup = value
Dim newValue As FixupCollection(Of NwlGroup) = TryCast(value, FixupCollection(Of NwlGroup))
If newValue IsNot Nothing Then
AddHandler newValue.CollectionChanged, AddressOf FixupNwlGroup
End If
End If
End Set
End Property
Private _nwlGroup As ICollection(Of NwlGroup)
...
End Class
然后我尝试将其序列化为xml
Dim ctx = New ModelEntities(_connectionString)
ctx.ContextOptions.ProxyCreationEnabled = False
ctx.ContextOptions.LazyLoadingEnabled = False
Dim customers = From c In ctx.NwlCustomer
Select c
Where c.SiID = 99
Dim filename As String = "C:\test.txt"
Dim result As NewsletterCustomer = customers.ToList.FirstOrDefault
Dim writer As New FileStream(filename, FileMode.Create)
Dim ser As New DataContractSerializer(GetType(NewsletterCustomer))
ser.WriteObject(writer, customers.ToList.FirstOrDefault)
writer.Close()
这给了我NewsletterCustomer xml,其中所有的读/写属性都是序列化的,就像没有指定DataContract时那样 . 如果我将DataContract属性从NewsletterCustomerMetadata移动到NewsletterCustomer,那么我只会在没有DataMember属性的情况下指定DataContract时获得根节点 .
看起来DataContractSerializer不适用于MetaDataType数据注释 .
我的问题是:
-
如何将POCO类序列化为CUSTOM XML?
-
如何将[DataContract]和[DataMember]属性添加到自动生成的POCO类中?
-
将自动生成的POCO类序列化为XML的最佳方法是什么?
3 回答
DataContractSerializer
不与旧的合作,这正是这种情况 .最好的方法是使用_2575304中的自定义序列化或@Marc建议的DTO . 如果是
DataContractSerializer
,您也可以使用IDataContractSurrogate
. 非常高级的XmlSerializer
场景是overriding XML serialization .也可以让T4模板为您生成属性,但这是非常先进的技术,因为它需要两个步骤:
手动修改EDMX文件(作为XML)并将结构注释添加到CSDL部分(定义实体的部分) . 结构注释是自定义XML元素 . Example of using structural annotation在反向过程中(控制SQL生成) .
修改T4模板以加载自定义结构注释并在类生成中使用它们 .
嗯,是的:xml是树格式 - 它不会喜欢循环引用 .
DataContractSerializer
不允许对xml进行相同级别的控制,所以我的建议是:在这种情况下坚持XmlSerializer
,并且 remove your circular references (通常在父属性上有一些[XmlIgnore]
) .否则:实现
IXmlSerializable
,但请注意,这几乎不提供任何元数据,并且是一个非常痛苦的做法 .您的问题已得到解答,但我在此处添加了我的解决方法,以帮助那些高度依赖XML序列化的人 . 当然,循环引用并不适合XML,但令人惊讶的是,它完全取代了XML .
我使用Code First并从EDMX生成POCO类 . 我自定义T4模板,使每个实体类都有ToXmlElement和FromXmlElement .
这些功能有能力:
完全丢弃循环引用 .
包含预定义数量的循环依赖关系 .
这是代码 . 不要担心晦涩的名字 . 图示的重点是,这是所有生成的代码,它处理本机类型,复杂类型,外键和子对象(多端) . 最后,它不会与EF对您的POCO类强加的FixUpCollection冲突 .