以XML存储关系数据

时间:2020-03-06 14:48:16  来源:igfitidea点击:

我想知道在XML中存储关系数据结构的最佳实践是什么。特别是,我想知道执行节点顺序的最佳实践。例如,假设我有三个对象:"学校","课程"和"学生",它们的定义如下:

class School
{
    List<Course> Courses;
    List<Student> Students;
}

class Course
{
    string Number;
    string Description;
}

class Student
{
    string Name;
    List<Course> EnrolledIn;
}

我将这样的数据结构存储在XML中,如下所示:

<School>
    <Courses>
        <Course Number="ENGL 101" Description="English I" />
        <Course Number="CHEM 102" Description="General Inorganic Chemistry" />
        <Course Number="MATH 103" Description="Trigonometry" />
    </Courses>
    <Students>
        <Student Name="Hyman">
            <EnrolledIn>
                <Course Number="CHEM 102" />
                <Course Number="MATH 103" />
            </EnrolledIn>
        </Student>
        <Student Name="Jill">
            <EnrolledIn>
                <Course Number="ENGL 101" />
                <Course Number="MATH 103" />
            </EnrolledIn>
        </Student>
    </Students>
</School>

按照这种方式对XML进行排序后,我可以首先解析Courses。然后,当我解析"学生"时,我可以在" School.Courses"列表中查找" EnrolledIn"(按其" Number")中列出的每个" Course"。这将为我提供一个对象引用,以添加到"学生"中的" EnrolledIn"列表中。但是,如果"学生"早于"课程",则无法进行这样的查找以获取对象引用。 (由于尚未填入" School.Courses"。)

那么在XML中存储关系数据的最佳实践是什么?
我是否应该强制要求"课程"必须始终在"学生"之前?
每当遇到一个尚未见过的对象时,是否应该允许任何排序并创建一个存根对象" Course"对象? (待以后最终达到"课程"的定义时进行扩展。)
我还有其他方法可以将对象持久化到XML中或者从XML中加载对象吗? (我目前正在所有业务对象上实现"保存"和"加载"方法,并使用" System.Xml.XmlDocument"及其相关类手动进行所有操作。)

我习惯于使用SQL之外的关系数据,但这是我第一次尝试以XML存储非平凡的关系数据结构的经验。我们能提供有关我应该如何进行的任何建议,将不胜感激。

解决方案

从经验来看,XML并不是存储关系数据的最佳方法。我们调查过YAML吗?你有选择吗?

如果不这样做,一种安全的方法是为XML设置严格的DTD并强制执行。如我们所建议,我们还可以保留创建的对象的哈希值。这样,如果学生创建课程,则可以保留该课程,以便将来在命中标签时进行更新。

还请记住,我们可以使用XPath查询直接访问特定节点,因此无论XML文档中的位置如何,都可以首先强制进行课程分析。 (由于使用了dacracot,因此可以提供更完整的答案)

虽然我们可以使用<xsd:sequence>指定子元素的顺序,但通过要求子对象按特定顺序排列,则会使系统的灵活性降低(即,更难使用记事本更新)。

最好的办法是解析所有数据,然后执行需要执行的操作。在解析过程中不要行动。

显然,XML的设计及其背后的数据使得无法将单个POCO序列化为XML。我们需要控制序列化和反序列化逻辑,以将对象解钩和重新钩在一起。

我建议创建一个自定义的序列化程序,以构建该对象图的xml表示形式。因此,它不仅可以控制序列化的顺序,还可以处理节点不在预期顺序中的情况。我们可以执行其他操作,例如添加自定义属性以将对象链接在一起,而这些属性在序列化的对象上不作为公共属性存在。

创建xml就像遍历对象几次一样简单,使用对象的预期表示形式以xml的形式构建XElement的集合。完成后,我们可以将它们缝合在一起成为XDocument,并从中获取xml。我们可以在反面的xml上进行多次传递,以重新创建对象图并恢复所有引用。

在XML中,顺序通常并不重要。在这种情况下,"课程"可以排在"学生"之后。我们解析XML,然后对整个数据进行查询。

XML绝对不是关系数据的友好之地。

如果我们绝对需要这样做,那么我建议我们使用一种时髦的倒置逻辑。

在示例中,我们拥有学校,该学校提供许多学生选择的许多课程。

XML可能如下所示:

<School>
    <Students>
        <Student Name="Hyman">
            <EnrolledIn>
                <Course Number="CHEM 102" Description="General Inorganic Chemistry" />
                <Course Number="MATH 103" Description="Trigonometry" />
            </EnrolledIn>
        </Student>
        <Student Name="Jill">
            <EnrolledIn>
                <Course Number="ENGL 101" Description="English I" />
                <Course Number="MATH 103" Description="Trigonometry" />
            </EnrolledIn>
        </Student>
    </Students>
</School>

这显然不是执行此操作的最重复的方法(它是关系数据!),但是它很容易解析。

使用XML时不要考虑使用SQL或者关系式,因为没有顺序限制。

但是,我们可以随时使用XPath查询XML文档的任何部分。我们首先要课程,然后是" //课程/课程"。我们要接下来的学生入学,然后是" //学生/学生/已入学/课程"。

最重要的是...仅仅因为XML存储在文件中,所以不要以为所有访问都是串行访问就可以了。

我提出了一个单独的问题," XPath可以在XML的两个子树之间执行外键查找吗?",以阐明我的立场。该解决方案说明了如何使用XPath对XML数据进行关系查询。

仅当我们需要对数据进行仅前向处理时,节点排序才是重要的。使用XmlReader或者SAX解析器。如果要在处理XML之前将XML读入DOM(如果使用XmlDocument,则是XML),那么节点顺序并不重要。更重要的是,XML被结构化,以便我们可以有效地使用XPath查询它,即不必使用" //"。

如果查看一下DataSetGenerator生成的架构,我们会发现与DataTable级元素没有任何关联。可能是ADO以某种方式处理了模式中未表示的元素(例如一次只处理一个DataTable),也可能是ADO执行了仅前向处理并且没有强制执行关系约束,直到完全读取了DataSet。我不知道。但是很明显,ADO不会将处理顺序与文档顺序耦合在一起。

(是的,我们可以在XML模式中指定子元素的顺序;这就是xs:sequence的作用。如果我们不希望强制执行节点顺序,请使用无限制的xs:choice。)

我们还可以使用两个XML文件,一个用于课程,另一个用于学生。打开并解析第一个,然后再执行第二个。

我已经有一段时间了,但是我似乎还记得在xml文件的一部分中进行了"事物"的基本集合,并使用了模式功能keyref和Refer在另一个中引用了它们。我在这里找到了一些例子。如果这不是我们要的内容,我深表歉意。