8

我的存储库有List<Student>List<Course>并且List<Enrolment>Enrollment 有 Enrolment.Student 和 Enrolment.Course ,它们是前两个列表中的学生或课程之一的引用。

当我在我的存储库上使用 XmlSerializer 时,它会输出冗余数据,因为它会序列化每个学生的所有属性,List<Student>然后再次对List<Enrolment>. 我正在寻找一种优雅的方法来解决这个问题。

反序列化后,我可以使用反序列化创建的重复对象实例中的 ID 值来修复引用,但这似乎很不自然。

修复冗余输出的一种方法是 XmlIgnore Enrolment.Student 和 Enrolment.Course 并为序列化创建另外两个属性 - Enrolment.StudentID 和 Enrolment.CourseID。但是,在反序列化期间,无法设置 Enrolment.Student 和 Enrolment.Course 的引用(AFAIK),因为反序列化的结果List<Student>不可List<Course>用。

我想到的另一种方法是在我的对象层次结构中序列化较低,分别执行我的每个列表并控制反序列化的顺序 - 我宁愿不这样做。

另一种方法是 XmlIgnoreList<Enrolment>并创建一个注册序列化助手类,该类List<Enrolment>在自身的反序列化完成后进行初始化。这似乎是一个很大的努力。

其他人如何使用 XmlSerializer 序列化/反序列化对同一对象的多个引用?

4

5 回答 5

3

哦,序列化的痛苦:-> ...

从来没有一个通用的解决方案,我想这就是为什么 MS 将它从 Silverlight 框架中剥离出来。

我从不依赖 .net 框架的任何自动序列化机制。对于我自己的模型和存储库,我通常知道或可以很容易地以编程方式确定哪些属性是简单的标量(数字/字符串/等),哪些是指向其他对象的链接(以及哪些是两者的列表)。

基本上有两种情况:

1:我们只想序列化/传输对象的平面信息。在这种情况下,我只传输链接到其他对象的属性的相应 ID。然后接收者可以进行后续查询以获取他们需要的所有其他对象。

2:我们希望传递尽可能多的信息,即具有多个级别的更深层次的嵌套 XML,主要用于某些报告功能,仅使用 XML 上的一些 CSS 直接显示所有内容。在这种情况下,实际上希望将相同的对象多次解析到 XML 树中。

有时我需要稍微调整第一个场景以避免过多的后续查询调用,但通常我相处得很好。即我已经在我们的代码库中构建了我们可以指定我们想要在何时解析哪些附加对象,和/或它在某处配置。

于 2010-01-08T11:25:52.493 回答
2

没有使用 XML 序列化程序解决此问题的方法。它没有可以用来删除重复的身份概念。

您可以做的最好的事情是将对象池与其引用分开序列化。然后,您可以在反序列化后重新创建列表。

顺便说一句,您是否知道 XmlSerializer 不是特定于 C# 的?

于 2010-01-08T08:22:10.883 回答
2

您可以为 Enrollment 实现接口 IXmlSerializable 并在 WriteXml 方法中生成仅包含键的学生和课程 XML,例如:

<Student Id="5"/>
<Course Id="6"/>

在 ReadXml 方法中,您可以从中加载引用。您还必须将 XmlIgnore 属性设置为 Student 和 Course 属性。

于 2010-01-08T08:32:55.247 回答
0

这听起来如何作为解决方案:

  1. XML忽略每个辅助参考,即 Enrolment.Student & Enrolment.Course
  2. 为每个辅助引用创建一个属性,用于序列化/反序列化该引用的外键 - 前缀为 XML_FK。例如 XML_FK_Student & XML_FK_Course
  3. 创建一个方法 XML_FinalizeDeserialization 在反序列化后调用,以使用这些外键属性加载引用。
于 2010-01-08T14:30:43.127 回答
0

您应该/可以将引用跟踪与 datacontract 序列化程序一起使用:

//deserilaize:
using(MemoryStream memStmBack = new MemoryStream()) {
  var serializerForth = new DataContractSerializer(
    typeof(YourType),
    null,
    0x7FFF /*maxItemsInObjectGraph*/ ,
    false /*ignoreExtensionDataObject*/ ,
    true /*preserveObjectReferences*/ ,
    null /*dataContractSurrogate*/ );

  byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
  memStmBack.Write(data, 0, data.Length);
  memStmBack.Position = 0;
  var lsBack = (YourType) serializerForth.ReadObject(memStmBack);

}
//serialize...
using(MemoryStream memStm = new MemoryStream()) {
    var serializer = new DataContractSerializer(
      typeof(YourType),
      knownTypes,
      0x7FFF /*maxItemsInObjectGraph*/ ,
      false /*ignoreExtensionDataObject*/ ,
      true /*preserveObjectReferences*/ ,
      null /*dataContractSurrogate*/ );

    serializer.WriteObject(memStm, yourType);

    memStm.Seek(0, SeekOrigin.Begin);

    using(var streamReader = new StreamReader(memStm)) {
        result = streamReader.ReadToEnd();

或使用

[Serializable]
[DataContract(IsReference = true)]
于 2018-08-29T09:09:02.237 回答