我有两个相互引用的课程:
[DataContract(IsReference = true)]
public class Student
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Surname { get; set; }
[DataMember]
public List<Course> Courses { get; set; }
public Student()
{
Courses = new List<Course>();
}
}
[DataContract(IsReference = true)]
public class Course
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public List<Student> Students { get; set; }
public Course()
{
Students = new List<Student>();
}
}
我想序列化4个学生实体,每个实体都附有一些课程。序列化后,只有第一个Student实体显示为空。更重要的是,它有太多的参考水平。而所有其他学生实体都是空的:
<GetStudentsResult
xmlns:a="http://schemas.datacontract.org/2004/07/WcfService2"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
z:Id="i1">
<a:Courses>
<a:Course z:Id="i2">
<a:Id>1</a:Id>
<a:Name>Operation Systems</a:Name>
<a:Students>
<a:Student z:Ref="i1"/>
<a:Student z:Id="i3">
<a:Courses>
<a:Course z:Ref="i2"/>
<a:Course z:Id="i4">
<a:Id>2</a:Id>
<a:Name>Algorithmes and data structures</a:Name>
<a:Students>
<a:Student z:Ref="i3"/>
<a:Student z:Id="i5">
<a:Courses>
<a:Course z:Ref="i4"/>
<a:Course z:Id="i6">
<a:Id>3</a:Id>
<a:Name>Basics of HTML and CSS</a:Name>
<a:Students>
<a:Student z:Ref="i1"/>
<a:Student z:Id="i7">
<a:Courses>
<a:Course z:Ref="i2"/>
<a:Course z:Ref="i6"/>
</a:Courses>
<a:Id>3</a:Id>
<a:Name>Oleg</a:Name>
<a:Surname>Kuznetsov</a:Surname>
</a:Student>
<a:Student z:Ref="i5"/>
</a:Students>
</a:Course>
</a:Courses>
<a:Id>4</a:Id>
<a:Name>Olga</a:Name>
<a:Surname>Petrova</a:Surname>
</a:Student>
</a:Students>
</a:Course>
</a:Courses>
<a:Id>2</a:Id>
<a:Name>Maria</a:Name>
<a:Surname>Vasilyeva</a:Surname>
</a:Student>
<a:Student z:Ref="i7"/>
</a:Students>
</a:Course>
<a:Course z:Ref="i6"/>
</a:Courses>
<a:Id>1</a:Id>
<a:Name>Egor</a:Name>
<a:Surname>Ivanov</a:Surname>
</a:Student>
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
z:Ref="i3"/>
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
z:Ref="i7"/>
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
z:Ref="i5"/>
</GetStudentsResult>
这是我的代码,填写学生和课程集:
Student s1 = new Student { Id = 1, Name = "Egor", Surname = "Ivanov" };
Student s2 = new Student { Id = 2, Name = "Maria", Surname = "Vasilyeva" };
Student s3 = new Student { Id = 3, Name = "Oleg", Surname = "Kuznetsov" };
Student s4 = new Student { Id = 4, Name = "Olga", Surname = "Petrova" };
context.Students.Add(s1);
context.Students.Add(s2);
context.Students.Add(s3);
context.Students.Add(s4);
Course c1 = new Course
{
Id = 1,
Name = "Operation Systems",
Students = new List<Student>() { s1, s2, s3 }
};
Course c2 = new Course
{
Id = 2,
Name = "Algorithmes and data structures",
Students = new List<Student>() { s2, s4 }
};
Course c3 = new Course
{
Id = 3,
Name = "Basics of HTML and CSS",
Students = new List<Student>() { s3, s4, s1 }
};
context.Courses.Add(c1);
context.Courses.Add(c2);
context.Courses.Add(c3);
请告知。
答案 0 :(得分:1)
您所看到的不是错误。数据协定序列化程序的IsReference = true
功能永远不会在XML文件中创建forward declarations ,只会向后引用。我们来看一个简单的案例:
[DataContract(IsReference = true, Namespace="")]
public class Item
{
[DataMember]
public int Id { get; set; }
[DataMember]
public Item SubItem { get; set; }
}
public class TestClass
{
public static void TestSimple()
{
var item1 = new Item { Id = 1 };
var item2 = new Item { Id = 2 };
item1.SubItem = item2;
var xml = DataContractSerializerHelper.GetXml(new[] { item1, item2 });
Debug.WriteLine(xml);
}
}
此测试用例创建的XML如下所示:
<ArrayOfItem xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Item z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>1</Id>
<SubItem z:Id="i2">
<Id>2</Id>
<SubItem i:nil="true" />
</SubItem>
</Item>
<Item z:Ref="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
</ArrayOfItem>
这意味着:
z:Id="i1"
z:Id="i2"
z:Id="i2"
出现。 即,在序列化时,数据契约序列化程序遇到引用对象的第一时间,它为其分配引用ID,将该id保存在字典中,然后继续序列化该对象。然后,在随后的遭遇中,它序列化对该id的引用,而不是其他任何内容。然后,在反序列化时,它执行相反的操作:当作为元素的属性遇到引用id时,为该元素创建的对象被放入字典中,然后被反序列化。在随后遇到该id时,保存的对象从字典中获取并插入到对象图中。
这种简单的一次通过算法不允许前向声明。
您似乎更希望在XML中以最高级别序列化引用对象,并在嵌套元素中根据需要插入前向或后向引用,如下所示:
<ArrayOfItem xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Item z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>1</Id>
<SubItem z:Ref="i2"/> <!-- FORWARD DECLARATION OF z:Id="i2" -->
</Item>
<Item z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>2</Id>
<SubItem i:nil="true" />
</Item>
</ArrayOfItem>
不幸的是,数据联系人序列化程序并没有这样做。
您可以看到,通过缩进您的XML,所有学生都被正确包含 - 除了第一个学生的课程列表中的第一个嵌套元素之外的所有学生。然后后续出现只是引用:
<GetStudentsResult xmlns:a="http://schemas.datacontract.org/2004/07/WcfService2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<a:Courses>
<a:Course z:Id="i2">
<a:Id>1</a:Id>
<a:Name>Operation Systems</a:Name>
<a:Students>
<a:Student z:Ref="i1" />
<a:Student z:Id="i3">
<a:Courses>
<a:Course z:Ref="i2" />
<a:Course z:Id="i4">
<a:Id>2</a:Id>
<a:Name>Algorithmes and data structures</a:Name>
<a:Students>
<a:Student z:Ref="i3" />
<a:Student z:Id="i5">
<a:Courses>
<a:Course z:Ref="i4" />
<a:Course z:Id="i6">
<a:Id>3</a:Id>
<a:Name>Basics of HTML and CSS</a:Name>
<a:Students>
<a:Student z:Ref="i1" />
<a:Student z:Id="i7">
<a:Courses>
<a:Course z:Ref="i2" />
<a:Course z:Ref="i6" />
</a:Courses>
<a:Id>3</a:Id>
<a:Name>Oleg</a:Name>
<a:Surname>Kuznetsov</a:Surname>
</a:Student>
<a:Student z:Ref="i5" />
</a:Students>
</a:Course>
</a:Courses>
<a:Id>4</a:Id>
<a:Name>Olga</a:Name>
<a:Surname>Petrova</a:Surname>
</a:Student>
</a:Students>
</a:Course>
</a:Courses>
<a:Id>2</a:Id>
<a:Name>Maria</a:Name>
<a:Surname>Vasilyeva</a:Surname>
</a:Student>
<a:Student z:Ref="i7" />
</a:Students>
</a:Course>
<a:Course z:Ref="i6" />
</a:Courses>
<a:Id>1</a:Id>
<a:Name>Egor</a:Name>
<a:Surname>Ivanov</a:Surname>
</a:Student>
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Ref="i3" />
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Ref="i7" />
<a:Student xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Ref="i5" />
</GetStudentsResult>
如果您使用DataContractSerializer
反序列化该XML,您会发现使用与原始图形相同的拓扑正确还原的学生和课程图表。