扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:冷枫 来源:CSDN 2007年9月24日
关键字:
在本页阅读全文(共2页)
数据集的 XML 表示形式可以使用 WriteXml 方法写入文件、流、XmlWriter 对象或字符串。XML 表示形式可以包括架构信息,也可以不包括架构信息。WriteXml 方法的实际行为可通过您可以传递的 XmlWriteMode 参数来控制。XmlWriteMode 枚举中的值决定着输出的布局。数据集表示形式包括表、关系和约束定义。如果您不选择使用 DiffGram 格式,数据集的表中的行就只写入其当前版本。下表概括了 XmlWriteMode 可以使用的写选项。
IgnoreSchema |
将数据集内容作为没有架构的 XML 数据写入 |
WriteSchema |
写入具有嵌入式 XSD 架构的数据集内容 |
DiffGram |
将数据集内容作为 DiffGram 写入,包括原始值和当前值 |
XmlWriteMode.IgnoreSchema 是默认选项。下面的代码显示了将数据集序列化为 XML 的典型方式。
// ds is the DataSetStreamWriter sw = new StreamWriter(fileName);ds.WriteXml(sw); // defaults to XmlWriteMode.IgnoreSchemasw.Close();
有几个因素影响了从 DataSet 对象创建的 XML 文档的最终结构。这些因素包括:
• |
使用的 XML 整体格式 — DiffGram 或当前内容的无格式分层表示形式 |
• |
架构信息是否存在 |
• |
嵌套关系 |
• |
表列如何映射到 XML 元素 |
DiffGram 格式是本人稍后将进一步说明的特殊 XML 格式。它不包括架构信息,但保留行状态和行错误。因而,它似乎能构成数据集实时实例的更接近的表示形式。
架构信息如果存在于所创建的数据集中,则将始终作为嵌入式 XSD 写入。您不可能将它作为 XDR、DTD 写入,或添加对外部文件的引用。如果尚未为生成的 XML 文件的根节点指定名称,则接受数据集的名称或 NewDataSet。下面的代码片段是由两个表组成的 DataSet 对象的 XML 表示形式的示例,这两个表是 Customers 和 Orders,它们之间的关系是通过 CustomerID 字段形成的。
<MyDataSet><xs:schema ... /><Customers><CustomerID>1</CustomerID><FName>John</FName><LName>Smith</LName></Customers><Customers><CustomerID>2</CustomerID><FName>Joe</FName><LName>Users</LName></Customers><Orders><CustomerID>1</CustomerID><OrderID>000A01</OrderID></Orders><Orders><CustomerID>1</CustomerID><OrderID>000B01</OrderID></Orders></MyDataSet>
您很难根据上面列出的代码判断出这两个表之间有关系。有关这方面的一些信息设置在 <xs:schema>树中,但除此之外,没有任何其他信息有助于推断出该结论。如果将在 CustomerID 字段上设定的关系归纳成文字,则可表达为 — 某个给定客户发出的所有定单。上面的 XML 树不提供此信息的立即表示形式。当数据集中存在数据关系时,要更改节点的顺序,可以将 DataRelation 对象的 Nested 属性设置为 true。作为此更改的结果,从更改得出的 XML 代码如下所示:
<MyDataSet><xs:schema ... /><Customers><CustomerID>1</CustomerID><FName>John</FName><LName>Smith</LName><Orders> <CustomerID>1</CustomerID> <OrderID>000A01</OrderID></Orders><Orders> <CustomerID>1</CustomerID> <OrderID>000B01</OrderID></Orders></Customers><Customers><CustomerID>2</CustomerID><FName>Joe</FName><LName>Users</LName></Customers></MyDataSet>
正如您看到的那样,所有定单现在集中在相应的客户子树下。
默认情况下,在 XML 表中,列呈现为节点元素。不过,这只是一个可以在每列基础上进行调整的设置。DataColumn 对象有一个名为 ColumnMapping 的属性,它决定了该列如何以 XML 形式呈现。ColumnMapping 属性接受下面列出的 MappingType 枚举中的值。
Element |
映射到 XML 节点元素: <CustomerID>value</CustomerID> |
Attribute |
映射到 XML 节点属性: <Customers CustomerID=value> |
Hidden |
不显示在 XML 数据中,除非使用的是 DiffGram 格式 |
SimpleContent |
映射到简单文本: <Customers>value</Customers> |
如果 XML 输出格式是 DiffGram,则忽略 Hidden 映射类型。不过,在这种情况下,列的 DiffGram 表示形式包含一个特殊属性,它将列标记为最初针对 XML 序列化隐藏起来。SimpleContent 映射类型并非始终可用,只有当表中有列的时候才可以使用。
DiffGram 只是一个根据表示数据集内容的具体架构写入的 XML 字符串。它决不是 .NET 类型。下面的代码片段显示了如何将 DataSet 对象序列化到 DiffGram。
StreamWriter sw = new StreamWriter(fileName);ds.WriteXml(sw, XmlWriteMode.DiffGram);sw.Close();
产生的 XML 代码放在<diffgr:diffgram> 节点中,最多包含三个不同的数据节,如下所示:
<diffgr:diffgram><MyDataSet>:</MyDataSet><diffgr:before>:</diffgr:before><diffgr:errors>:</diffgr:errors></diffgr:diffgram>
DiffGram 的第一节是强制性的,表示数据的当前实例。它几乎与您可以从普通的序列化得到的 XML 输出完全相同。二者之间的主要区别是,DiffGram 格式从来不包括架构信息。
该数据节包括数据集中行的当前值。包括删除行在内的原始行存储在 <diffgr:before>节中。这里只列出了修改的记录或删除的记录。新添加的记录只在数据实例中列出,因为它们没有所要链接到的前述引用。这两节中的行是使用唯一 ID 进行跟踪的。这些行表示数据集的原始版本和当前版本之间的增量。
最后,在 <diffgr:errors>节列出与行上挂起的错误相关的任何消息。同样,在这种情况下,使用讨论是否要进行更改的相同的唯一 ID 来跟踪行。DiffGram 节点可以用特殊属性标记为跨不同的节(数据实例、更改和错误)使元素相关。
diffgr:hasChanges |
该行已被修改(请参见 <diffgr:before>中的相关行)或插入。 |
diffgr:hasErrors |
该行有错误(请参见 中的相关行)。 |
diffgr:id |
确定用于跨节耦合行的 ID:TableName+RowIdentifier。 |
diffgr:parentId |
确定用于标识当前行的父行的 ID。 |
diffgr:error |
包含 <diffgr:before>中的行的错误文本。 |
msdata:rowOrder |
跟踪数据集中的行的序号位置。 |
diffgr:hidden |
确定被标记为隐藏的 msdata:hiddenColumn= ???… 的列。 |
ADO.NET 框架只对 DataSet 对象提供显式 XML 支持。不过,将 DataView 或 DataTable 转换为 XML 并不是特别难。在这两种情况下,您都必须使用临时的数据集作为要另存为 XML 的行集的容器。用于将 DataTable 保存为 XML 所必需的代码很简单。
void WriteDataTableToXml(String fileName, DataTable dt){// Duplicate the table and add it to a temporary DataSetDataSet dsTmp = new DataSet();DataTable dtTmp = dt.Copy();dsTmp.Tables.Add(dtTmp);// Save the temporary DataSet to XMLStreamWriter sr = new StreamWriter(fileName);dsTmp.WriteXml(sr);sr.Close();}
每个 ADO.NET 对象只能由一个容器对象引用,由于这个简单的原因,复制 DataTable 对象是非常重要的。您不能有相同的实例,例如,一个 DataTable 对象属于两个不同的 DataSet 对象。
与 DataTable 对象不同的是,DataView 不是数据集的标准组成部分,因此,为了将它保存到 XML,您应该将 DataView 转换为一个表对象。这个过程可用下面的代码片段来实现:
void DataViewToDataTable(DataView dv){// Clone the structure of the table behind the viewDataTable dtTemp = dv.Table.Clone();dtTemp.TableName = "Row"; // this is arbitrary!// Populate the table with rows in the viewforeach(DataRowView drv in dv)dtTemp.ImportRow(drv.Row);// giving a custom name to the DataSet can help to // come up with a clearer layout but is not mandatoryDataSet dsTemp = new DataSet(dv.Table.TableName); // Add the new table to a temporary DataSetdsTemp.Tables.Add(dtTemp);}
第一个步骤是,对所处理的 DataView 对象后面的表的结构进行克隆。接着,遍历此视图中的所有记录,并将相应的行添加到临时的 DataTable。然后,将此 DataTable 添加到临时数据集,并对该 DataTable 进行序列化。还可以设法向数据集提供表名,并向整个 XML 输出提供自定义格式。例如:
<TableName><Row><Column1>??</Column1>:</Row><Row>:</Row><Row>:</Row></TableName>
XML 和 ADO.NET 框架为访问以 XML 和关系数据的形式表示的数据提供了统一的模型。其中,关键的 XML 类是 XmlDataDocument,而 DataSet 则是关键的 ADO.NET 类。具体来说,XmlDataDocument 从基类 XmlDocument 继承,并且只是在与 DataSet 对象保持同步的能力方面与该基类有所不同。进行同步时,DataSet 类和 XmlDataDocument 类的目标是同一个行集合,并且您能够通过两个接口(节点和关系表)来应用更改,还可以使这两个类可以立即看到更改。基本上,DataSet 和 XmlDataDocument 为同一数据提供两套方法。因此,您可以将 XSLT 转换应用于关系数据,通过 XPath 表达式查询关系数据以及使用 SQL 来选择 XML 节点。
您可以通过几种方法将 DataSet 对象和 XmlDataDocument 对象绑定在一起。第一个方法是,将一个非空的 DataSet 对象传递到 XmlDataDocument 类的构造函数。
XmlDataDocument doc = new XmlDataDocument(dataset);
与其基类相似的是,XmlDataDocument 提供了一种使用 XML 数据的 XML DOM 方法,因而,它与 XML 读取器和编写器非常不同。下面的示例显示了对这两个对象进行同步的另一种方法,这就是从 XML DOM 的一个非空实例创建一个有效的非空 DataSet 对象。
XmlDataDocument doc = new XmlDataDocument();doc.Load(fileName);DataSet dataset = doc.DataSet;
您可以使用 XmlDataDocument 的 DataSet 属性将 XML 文档变成 DataSet 对象。该属性对 DataSet 对象进行实例化和填充,并返回该对象。在您第一次访问 DataSet 属性时,数据集就与 XmlDataDocument 相关联起来了。方法 GetElementFromRow 和 GetRowFromElement 在数据的 XML 形式和关系视图之间切换。为了从关系的角度查看 XML 数据,您必须先指定要用于数据映射的架构。可通过对同一个 XML 文件调用 ReadXmlSchema 方法来达到此目的。另一种方法是,您可以手动创建数据集中必需的表和列。
不过,还有一种同步 XmlDataDocument 和 DataSet 对象的方法,那就是当它们为空时,分别对其进行填充。例如:
DataSet dataset = new DataSet();XmlDataDocument xmldoc = new XmlDataDocument(dataset);xmldoc.Load("file.xml");
将两个对象保持同步可以提供前所未有的灵活性,正如前面所提到的,您可以使用两个截然不同的导航类型来在记录之间进行移动。实际上,您可以对 XML 节点使用类似 SQL 的查询,以及对关系行使用 XPath 查询。
并非所有 XML 文件都可以成功地与数据集同步。为了保持同步,XML 文档必须有一个可以映射到关系结构的正规表格式结构,在关系结构中,每一行都有相同数量的列。XML 文档在呈现为 DataSet 对象时,将丢失任何 XML 特定的信息,这些信息可能是它们已经拥有的,并且没有关系上的对应部分。这些信息包括注释、声明和处理指令。
在 ADO.NET 中,XML 不仅仅是用于对内容进行序列化的简单输出格式。您可以使用 XML 对 DataSet 对象的整个内容进行序列化,但您也可以选择实际的 XML 架构并控制所得到的 XML 文档的结构。您可以监视数据集的内容,包括表和关系,可以接受最终文档得出的架构信息,甚至还可以采用 DiffGram 格式。
当 ADO.NET 与 XML 进行交互和集成时,可以提供更多的特性。特别是,在 .NET 中,您可以同时提供和利用同一数据的两个同等但独立的视图,它们遵循着不同的逻辑数据表示形式。
我已经发现,数据集编程接口提供了名为 GetChanges 的方法,该方法返回一个更小的数据集,这个数据集只填充了所有包括的表中那些更新过的行。因此,这使我认为,使用这个更小的数据集而不是那个原始数据集可以提高性能。不过,您在上一篇文章中提到过某种情况,文章名称和出处我记不清了,说这种情况已引发出一些尚未确定的异常。因此,我的问题是,您是否能更清楚地说明一下数据集的 GetChanges 方法在批处理更新中的使用?
ADO.NET 批处理更新基于对指定表上的行进行遍历的循环。代码检查行的状态,并决定要执行哪个操作。该循环作用于您作为参数提供给适配器的方法 Fill 的数据集和数据表。如果您对原始数据集或对由 GetChanges 返回的更小的数据集调用 Fill,结果将大致相同。这样做将导致优化程度最低,并且只起到了缩小循环长度的作用。
在批处理更新过程中,数据行是按从中间层到数据服务器的顺序进行处理的。不存在一次性地或作为单一数据块发送到数据库的数据快照。实际上,在这种情况下,使用 GetChanges 将获得优化程度大得多的代码。
决定在批处理更新期间如何执行许多重要操作的关键参数是所修改的行的数量。无论您使用的是原始数据集还是由 GetChanges 返回的数据集,该参数都不更改。
相反,如果您对由 GetChanges 返回的数据集进行批处理更新,当检测到冲突时,您可能会遇到严重的问题。在这种情况下,在失败的行之前处理的行将正常提交,但它们不在原始数据集上!要确保应用程序的一致性,您必须接受提交的行上的更改,以及原始数据集上的更改。此代码完全是独立的。总而言之,如果您使用原始数据集,则批处理更新代码要简单得多。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=356362
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者