|
||||||||||||||||||||||||
|
ГЛАВА 10ADO.NET и XML Оставляя в стороне маркетинговую шумиху, следует отметить, что XML действительно способствует выполнению множества задач, связанных с программированием бизнес-решений. Это особенно верно в тех случаях, когда огромное значение приобретает интеграция разных систем и платформ в рамках одной или нескольких компаний. Поэтому при создании интегрированной среды разработки Visual Studio .NET одной из основных целей была расширенная поддержка XML. Язык XML является форматом устойчивого хранения объекта DataSet, т.е. при сохранении на жестком диске объекта DataSet используется универсальный формат XML, а не двоичный или какой-то другой специализированный формат. Аналогично, при обмене объектами DataSet между разными процессами или компьютерами данные передаются в потоке формата XML. В прежних главах показано, что объект DataSet не зависит от источника данных, которые он содержит. Для него данные — это всего лишь данные, независимо от их происхождения. То же самое верно, когда источник данных имеет формат XML. Объект DataSet обладает средствами чтения и записи данных в формате XML и/или информации о схеме данных. В модели ADO.NET эти средства обладают гораздо более высокими функциональными возможностями по сравнению с моделью ADO. Более того, благодаря объекту XmlDataDocument приложение может просматривать данные объекта DataSet и манипулировать ими с помощью реляционных инструментов и/или XML-инструментов, в зависимости от ситуации. Полное описание XML и связанных с ним технологий и инструментов выходит за рамки данной книги. В главе 9, "XML и .NET", представлены основные сведения о расширенной поддержке XML на платформе.NET Framework, а в этой главе описываются основы интеграции ADO.NET и платформы .NET Framework. Более подробную информацию об этом можно найти в справочных материалах Visual Studio .NET и платформы .NET Framework, а также на Web-узле MSDN по адресу: http://msdn.microsoft.com. Основные принципы чтения и записи XML-данныхВ главах 5, "ADO.NET: объект DataSet", и 6, "ADO.NET: объект DataAdapter" демонстрируются программируемые и прямые способы загрузки данных в объект DataSet из базы данных. Еще один метод загрузки данных основан на чтении XML-данных. Как и следовало ожидать, в объект DataSet данные можно записывать в XML-формате. Более того, объект DataSet обладает средствами чтения и записи XML-схем либо вместе с XML-данными, либо раздельно. Чтение XML-данныхВ ADO.NET предусмотрены богатые и разнообразные инструменты чтения и записи XML-данных и XML-схем. Далее рассматриваются основные способы использования предназначенных для этого методов и свойств. Как и в предыдущих главах, для демонстрации взаимодействия модели ADO.NET и XML здесь приводится практический пример их использования на основе простой формы. 1. Запустите интегрированную среду разработки Visual Studio .NET и создайте новый проект Visual Basic Windows Application. Для этого в диалоговом окне New Project (Новый проект) выберите тип проекта Visual Basic Project в области Project Types (Типы проектов), а затем шаблон Windows Application (Приложение Windows) в области Templates (Шаблоны). 2. Назовите проект ADO-XML. 3. Укажите путь к файлам проекта. 4. Увеличьте размер формы Form1. 5. В окне свойств Properties укажите значение frmXML для свойства (Name) и значение ADO.NET and XML для свойства Text формы Form1. 6. В верхнем левом углу формы создайте кнопку, перетаскивая ее из панели элементов управления. 7. В окне свойств Properties укажите значение btnReadXML для свойства (Name) и значение Read XML для свойства Text этой кнопки. 8. В правой части формы создайте сетку DataGrid, перетаскивая ее из панели элементов управления. 9. В окне свойств Properties укажите значение grdData для свойства (Name) сетки. 10. Увеличьте размер сетки grdData, чтобы она занимала до 80% всей площади формы. В верхней части файла введите следующий код: Imports System Imports System.Data Imports System.Data.SqlClient Затем в определении класса формы frmXML введите код из листинга 10.1. Листинг 10.1. Код чтения содержимого XML-файла в объект DataSetPrivate Sub btnReadXML_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnReadXML.Click Dim dsPubs As New DataSet() ' Чтение XML-данных из файла. dsPubs.ReadXml("..\Pubs.xml") ' Связывание объекта DataSet с сеткой данных DataGrid. grdData.DataMember = "publishers" grdData.DataSource = dsPubs End Sub Эта подпрограмма считывает XML-данные из файла pubs.xml в объект DataSet. Теперь объект DataSet и его данные могут использоваться любым из способов, описанных в предыдущих главах. Кроме того, эта подпрограмма связывает объект DataSet с сеткой данных DataGrid. В листинге 10.2 показано содержимое файла pubs.xml, а на рис. 10.1 — данные в сетке DataGrid. РИС. 10.1. Содержимое файла pubs.xml в сетке DataGrid Листинг 10.2. Содержимое файла pubs. <?xml version="1.0" standalone="yes"?> <NewDataSet> <publishers> <pub_id>0736</pub_id> <pub_name>New Moon Books</pub_name> <city>Boston</city> <state>MA</state> <country>USA</country> </publishers> <publishers> <pub_id>0877</pub_id> <pub_name>Binnet & Hardley</pub_name> <city>Washington</city> <state>DC</state> <country>USA</country> </publishers> <publishers> <pub_id>1389</pub_id> <pub_name>Algodata Infosystems</pub_name> <city>Berkeley</city> <state>CA</state> <country>USA</country> </publishers> <publishers> <pub_id>1622</pub_id> <pub_name>Five Lakes Publishing</pub_name> <city>Chicago</city> <state>IL</state> <country>USA</country> </publishers> <publishers> <pub_id>1756</pub_id> <pub_name>Ramona Publishers</pub_name> <city>Dallas</city> <state>TX</state> <country>USA</country> </publishers> <publishers> <pub_id>9952</pub_id> <pub_name>Scootney Books</pub_name> <city>New York</city> <state>NY</state> <country>USA</country> </publishers> <publishers> <pub_id>9999</pub_id> <pub_name>Lucerne Publishing</pub_name> <countгу>France</country> </publishers> </NewDataSet> НА ЗАМЕТКУ В данном примере демонстрируется простейший способ чтения XML-данных в объект DataSet, т.е. чтение из файла. Помимо этого способа, существует много других вариантов чтения XML-данных с помощью перегруженных версий метода ReadXML, например с помощью объектов Stream, TextReader или XmlReader. Соответствующие им перегруженные версии метода ReadXML содержат второй параметр со значением XmlReadMode. Этот параметр используется для указания способа интерпретации содержимого XML-источника и обработки схемы данных. В табл. 10.1 приведено краткое описание членов перечисления XmlReadMode. Таблица 10.1. Перечисление XmlReadMode
Для чтения только схемы данных (и игнорирования данных) предусмотрена перегруженная версия метода ReadXmlSchema, которая может применяться для считывания схемы объектов DataTable объекта DataSet так, как показано ниже. MyDataSet.ReadXmlSchema("MySchemaFile.xml") Те же четыре источника данных (файл, объекты Stream, TextReader и XmlReader) могут использоваться вместе с методом ReadXmlSchema. Объект DataSet имеет аналогичный набор методов для записи XML-данных. Запись XML-данныхПосле загрузки в объект DataSet (независимо от способа и места загрузки) данные и/или схемы данных можно записать в XML-формате (с XML-схемой или без нее). Для демонстрации способов записи данных в XML-формате выполните перечисленные ниже действия. 1. Создайте в форме новую кнопку сразу под кнопкой Read XML, перетаскивая ее из панели инструментов. 2. В окне свойств Properties укажите значение btnWriteXML для свойства (Name) и значение Write XML для свойства Text этой кнопки. 3. Затем в определении класса формы frmXML введите код из листинга 10.3. Листинг 10.3. Код сохранения содержимого объекта DataSet в виде XML-файлаPrivate Sub btnWriteXML_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnWriteXML.Click Dim dsSales As New DataSet() Dim en As New SqlConnection _ ("data source=localhost;initial catalog=pubs;user id=sa") Dim daAuthors As New SqlDataAdapter("select * from sales", en) Dim daPublishers As New SqlDataAdapter("select * from stores", en) ' Загрузка реляционных данных из базы данных. daAuthors.Fill(dsSales, "Sales") daPublishers.Fill(dsSales, "Stores") ' Запись XML-данных в файл dsSales.WriteXml("…\StoreSales.xml") ' Запись схемы в XSD-файл. dsSales.WriteXmlSchema("…\StoreSales.xsd") End Sub В этой подпрограмме создаются два объекта — адаптера данных (daAuthors и daPublishers), которые затем используются для вставки данных в объект dsPubs из двух таблиц базы данных pubs СУБД SQL Server. В листинге 10.4 приведено содержимое файла StoreSales.xml, который создается в результате выполнения этой подпрограммы. Обратите внимание на то, что данный XML-документ содержит записи о продажах, а затем записи о магазинах. Этот подход имеет смысл, так как между ними не задано никакого отношения. Если бы таблицы Sales и Stores были связаны, то эти записи можно было вложить друг в друга. Пример такого вложения приводится далее, в бизнес-ситуации 10.1. ЛИСТИНГ 10.4. Содержимое файла StoreSales.xml<?xml version="1.0" standalone="yes"?> <NewDataSet> <Sales> <stor_id>6380</stor_id> <ord_num>6871</ord_num> <ord_date>l994-09-14T00:00:00.0000000+02:00</ord_date> <qty>5</qty> <payterms>Net 60</payterms> <title_id>BU1032</title_id> </Sales> <Sales> <stor_id>6380</stor_id> <ord_num>722a</ord_num> <ord_date>l994-09-13T00:00:00.0000000+02:00</ord_date> <qty>3</qty> <payterms>Net 60</payterms> <title_id>PS2091</title_id> </Sales> <Sales> <stor_id>7066</stor_id> <ord_num>A2976</ord_num> <ord_date>1993-05-24T00:00:00.0000000+02:00</ord_date> <qty>50</qty> <payterms>Net 30</payterms> <title_id>PC8888</title_id> </Sales> <Sales> <stor_id>7066</stor_id> <ord_num>QA7442.3</ord_num> <ord_date>1994-09-13T00:00:00.0000000+02:00</ord_date> <qty>75</qty> <payterms>ON invoice</payterms> <title_id>PS209K/title_id> </Sales> <Sales> <stor_id>7067</stor_id> <ord_num>D4482</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>Net 60</payterms> <title_id>PS2091</title_id> </Sales> <Sales> <stor_id>7067</stor_id> <ord_nurn>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>40</qty> <payterms>Net 30</payterms> <title_id>TC3218</title_id> </Sales> <Sales> <stor_id>7067</stor_id> <оrd_num>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>TC4203</title_id> </Sales> <Sales> <stor_id>7067</stor_id> <ord_num>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>TC7777</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <ord_num>N914008</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>PS2091</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <оrd_num>N914014</оrd_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 30</payterms> <title_id>MC3021</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 60</payterms> <title_id>PS1372</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 60</payterms> <title_id>PS2106</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>Net 60</payterms> <title_id>PS3333</title_id> </Sales> <Sales> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 60</payterms> <title_id>PS7777</title_id> </Sales> <Sales> <stor_id>7896</stor_id> <ord_num>QQ2299</ord_num> <ord_date>1993-10-28T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>Net 60</payterms> <title_id>BU7832</title_id> </Sales> <Sales> <stor_id>7896</stor_id> <ord_num>TQ456</ord_num> <ord_date>1993-12-12T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>Net 60</payterms> <title_id>MC2222</title_id> </Sales> <Sales> <stor_id>7896</stor_id> <ord_num>X999</ord_num> <ord_date>1993-02-21T00:00:00.0000000+02:00</ord_date> <qty>35</qty> <payterms>ON invoice</payterms> <title_id>BU2075</title_id> </Sales> <Sales> <stor_id>8042</stor_id> <ord_num>423LL922</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>ON invoice</payterms> <title_id>MC3021</title_id> </Sales> <Sales> <stor_id>8042</stor_id> <ord_num>423LL930</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>ON invoice</payterms> <title_id>BU1032</title_id> </Sales> <Sales> <stor_id>8042</stor_id> <ord_num>P723</ord_num> <ord_date>1993-03-11T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 30</payterms> <title_id>BU1111</title_id> </Sales> <Sales> <stor_id>8042</stor_id> <ord_num>QA879.1</ord_num> <ord_date>1993-05-22T00:00:00.0000000+02:00</ord_date> <qty>30</qty> <payterms>Net 30</payterms> <title_id>PC1035</title_id> </Sales> <Stores> <stor_id>6380</stor_id> <stor_name>Eric the Read Books</stor_name> <stor_address>788 Catamaugus Ave.</stor_address> <city>Seattle</city> <state>WA</state> <zip>98056</zip> </Stores> <Stores> <stor_id>7066</stor_id> <stor_name>Barnum's</stor_name> <stor_address>567 Pasadena Ave.</stor_address> <state>CA</state> <zip>92789</zip> </Stores> <Stores> <stor_id>7067</stor_id> <stor_name>News & Brews</stor_name> <stor_address>577 First St.</stor_address> <city>Los Gatos</city> <state>CA</state> <zip>96745</zip> </Stores> <Stores> <stor_id>7131</stor_id> <stor_name>Doc-U-Mat: Quality Laundry and Books</stor_name> <stor_address>24-A Avogadro Way</stor_address> <city>Remulade</city> <state>WA</state> <zip>98014</zip> </Stores> <Stores> <stor_id>7896</stor_id> <stor_name>Fricative Bookshop</stor_name> <stor_address>89 Madison St.</stor_address> <city>Fremont</city> <state>CA</state> <zip>90019</zip> </Stores> <Stores> <stor_id>8042</stor_id> <stor_name>Bookbeat</stor_name> <stor_address>679 Carson St.</stor_address> <city>Portland</city> <state>OR</state> <zip>89076</zip> </Stores> </NewDataSet> В приведенном примере демонстрируется простейший способ записи данных из объекта DataSet в XML-файл. Помимо этого способа существуют другие варианты записи данных и схемы с помощью перегруженных версий метода WriteXML. Соответствующие им перегруженные версии метода ReadXML содержат второй параметр со значением XmlWriteMode. В табл. 10.2 приведено краткое описание членов перечисления XmlWriteMode. Таблица 10.2. Перечисление XmlWriteMode
НА ЗАМЕТКУ Для записи схемы данных из объекта DataSet в отдельном XSD-файле (вместо встраивания ее в данные) предусмотрен метод WriteXmlSchema, который используется так, как показано ниже. dsSales.WriteXmlSchema В листинге 10.5 приведено содержимое файла StoreSales.xsd, полученного в результате выполнения этого метода. Листинг 10.5. Содержимое файла StoreSales.xsd, который является схемой из объекта dsSales<?xml version="1.0" standalone="yes"?> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:lsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Sales"> <xs:complexType> <xs:sequence> <xs:element name="stor_id" type="xs:string" minOccurs="0" /> <xs:element name="ord_num" type="xs:string" minOccurs="0" /> <xs:element name="ord_date" type="xs:dateTime" minOccurs="0" /> <xs:element name="qty" type="xs:short" minOccurs="0" /> <xs:element name="payterms" type="xs:string" minOccurs="0" /> <xs:element name="title_id" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Stores"> <xs:complexType> <xs:sequence> <xs:element name="stor_id" type="xs:string" minOccurs="0" /> <xs:element name="stor_name" type="xs:string" minOccurs="0" /> <xs:element name="stor_address" type="xs:string" minOccurs="0" /> <xs:element name="city" type="xs:string" minOccurs="0" /> <xs:element name="state" type="xs:string" minOccurs="0" /> <xs:element name="zip" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> Формат DiffCramРассмотрим теперь формат DiffGram, который используется членами перечислений XmlReadMode и XmlWriteMode. Это XML-формат, содержащий не только текущие значения элементов-данных, но и их исходные значения, которые были изменены или удалены (вслед за последним вызовом метода AcceptChanges). Итак, DiffGram представляет собой формат сериализации, который используется для передачи данных другому процессу или компьютеру. Поскольку эти данные фактически имеют XML-формат, они могут легко передаваться другим платформам, например UNIX или Linux. Каждый файл формата DiffGram имеет три раздела. Первый раздел содержит текущие значения всех записей объекта DataSet, независимо от того, изменялись они или нет. Любой измененный элемент (запись) обозначается как diffgr:hasChanges="modified", а любой добавленный элемент (запись) — как diffgr:hasChanges="inserted". Второй раздел содержит исходные значения всех измененных и удаленных записей. Его элементы связаны с соответствующими элементами первого раздела, которые обозначаются как diffgr:id="xxx", где ххх — идентификатор записи. Третий раздел содержит информацию об ошибках работы с записями. Его элементы связаны аналогичным образом с соответствующими элементами первого раздела, которые обозначаются как diffgr:id="xxx". Для генерации XML-файла в формате DiffGram нужно внести приведенные ниже изменения (они обозначены полужирным начертанием) в подпрограмму btnWriteXML_Click.H3 листинга 10.3. Private Sub btnWriteXML_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnWriteXML.Click Dim dsSales As New DataSet() Dim en As New SqlConnection _ ("data source=localhost;initial catalog=pubs;user id=sa") Dim daAuthors As New SqlDataAdapter("select * from sales ", en) Dim daPublishers As New SqlDataAdapter("select * from stores ", en) ' Загрузка реляционных данных из базы данных. daAuthors.Fill(dsSales, "Sales") daPublishers.Fill(dsSales, "Stores") ' Запись XML-данных в файл. dsSales.WriteXml("..\StoreSales.xml") ' Запись схемы в XSD-файл. dsSales.WriteXmlSchema("..\StoreSales.xsd") ' Пример изменения, удаления и вставки новой записи. dsSales.Tables("Stores").Rows(0)("stor_id") = 999 ' Изменение dsSales.Tables("Stores").Rows(1).Delete() ' Удаление Dim rr As DataRow = dsSales.Tables("Stores").NewRow() rr("stor_name") = "New Store" dsSales.Tables("Stores").Rows.Add(rr) ' Вставка ' Сохранение только измененных записей в формате DiffGram. Dim ChangedDataSet = dsSales.GetChanges() ChangedDataSet.WriteXml("…\Changes.xml", XmlWriteMode.DiffGram) ' Сохранение всех записей в формате DiffGram. dsSales.WriteXml("…\DiffGram.xml", XmlWriteMode.DiffGram) End Sub В листинге 10.6 приведено содержимое файла DiffGram.xml, полученного в результате щелчка на кнопке Write XML формы проекта ADO-XML. Внесенные в таблицу Stores изменения выделены полужирным начертанием. Удаленная запись отсутствует в разделе текущих данных, но присутствует в разделе исходного состояния вместе с исходным значением измененной записи. Кроме того, раздел с текущими данными содержит новую запись с отметкой "inserted" (вставлена). Листинг 10.6. XML-файл DiffGram.xml в формате DiffGram с одной вставленной записью, одной удаленной записью и одной измененной записью<?xml version="1.0" standalone="yes"?> <diffgr:diffgram xmlns:msdata="urn:schemes-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <NewDataSet> <Sales diffgr:id="Sales1" msdata:rowOrder="0"> <stor_id>6380</stor_id> <ord_num>6871</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>5</qty> <payterms>Net 60</payterms> <title_id>BU1032</title_id> </Sales> <Sales diffgr:id="Sales2" msdata:rowOrder="1"> <stor_id>6380</stor_id> <ord_num>722a</ord_num> <ord_date>1994-09-13T00:00:00.0000000+02:00</ord_date> <qty>3</qty> <payterms>Net 60</payterms> <title_id>PS2091</title_id> </Sales> <Sales diffgr:id="Sales3" msdata:rowOrder="2"> <stor_id>7066</stor_id> <ord_num>A2976</ord_num> <ord_date>1993-05-24T00:00:00.0000000+02:00</ord_date> <qty>50</qty> <payterms>Net 30</payterms> <title_id>PC8888</title_id> </Sales> <Sales diffgr:id="Sales4" msdata:rowOrder="3"> <stor_id>7066</stor_id> <ord_num>QA7442.3</ord_num> <ord_date>1994-09-13T00:00:00.0000000+02:00</ord_date> <qty>75</qty> <payterms>ON invoice</payterms> <title_id>PS2091</title_id> </Sales> <Sales diffgr:id="Sales5" msdata:rowOrder="4"> <stor_id>7067</stor_id> <ord_num>D4482</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>Net 60</payterms> <title_id>PS2091</title_id> </Sales> <Sales diffgr:id="Sales6" msdata:rowOrder="5"> <stor_id>7067</stor_id> <ord_num>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>40</qty> <payterms>Net 30</payterms> <title_id>TC3218</title_id> </Sales> <Sales diffgr:id="Sales7" msdata:rowOrder="6"> <stor_id>7067</stor_id> <ord_num>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>TC4203</title_id> </Sales> <Sales diffgr:id="Sales8" msdata:rowOrder="7"> <stor_id>7067</stor_id> <ord_num>P2121</ord_num> <ord_date>1992-06-15T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>TC7777</title_id> </Sales> <Sales diffgr:id="Sales9" msdata:rowOrder="8"> <stor_id>713K/stor_id> <ord_num>N914008</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 30</payterms> <title_id>PS2091</title_id> </Sales> <Sales diffgr:id="Sales10" msdata:rowOrder="9"> <stor_id>7131</stor_id> <ord_num>N914014</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 30</payterms> <title_id>MC3021</title_id> </Sales> <Sales diffgr:id="Sales11" msdata:rowOrder="10"> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>20</qty> <payterms>Net 60</payterms> <title_id>PS1372</title_id> </Sales> <Sales diffgr:id="Sales12" msdata:rowOrder="11"> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 60</payterms> <title_id>PS2106</title_id> </Sales> <Sales diffgr:id="Sales13" msdata:rowOrder="12"> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>Net 60</payterms> <title_id>PS3333</title_id> </Sales> <Sales diffgr:id="Sales14" msdata:rowOrder="13"> <stor_id>7131</stor_id> <ord_num>P3087a</ord_num> <ord_date>1993-05-29T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 60</payterms> <title_id>PS7777</title_id> </Sales> <Sales diffgr:id="Sales15" msdata:rowOrder="14"> <stor_id>7896</stor_id> <ord_num>QQ2299</ord_num> <ord_date>1993-10-28T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>Net 60</payterms> <title_id>BU7832</title_id> </Sales> <Sales diffgr:id="Sales16" msdata:rowOrder="15"> <stor_id>7896</stor_id> <ord_num>TQ456</ord_num> <ord_date>1993-12-12T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>Net 60</payterms> <title_id>MC2222</title_id> </Sales> <Sales diffgr:id="Sales17" msdata:rowOrder="16"> <stor_id>7896</stor_id> <ord_num>X999</ord_num> <ord_date>1993-02-21T00:00:00.0000000+02:00</ord_date> <qty>35</qty> <payterms>ON invoice</payterms> <title_id>BU2075</title_id> </Sales> <Sales diffgr:id="Sales18" msdata:rowOrder="17"> <stor_id>8042</stor_id> <ord_num>423LL922</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>15</qty> <payterms>ON invoice</payterms> <title_id>MC3021</title_id> </Sales> <Sales diffgr:id="Sales19" msdata:rowOrder="18"> <stor_id>8042</stor_id> <оrd_num>423LL930</ord_num> <ord_date>1994-09-14T00:00:00.0000000+02:00</ord_date> <qty>10</qty> <payterms>ON invoice</payterms> <title_id>BU1032</title_id> </Sales> <Sales diffgr:id="Sales20" msdata:rowOrder="19"> <stor_id>8042</stor_id> <ord_num>P723</ord_num> <ord_date>1993-03-11T00:00:00.0000000+02:00</ord_date> <qty>25</qty> <payterms>Net 30</payterms> <title_id>BU1111</title_id> </Sales> <Sales diffgr:id="Sales21" msdata:rowOrder="20"> <stor_id>8042</stor_id> <ord_num>QA879.1</ord_num> <ord_date>1993-05-22T00:00:00.0000000+02:00</ord_date> <qty>30</qty> <payterms>Net 30</payterms> <title_id>PC1035</title_id> </Sales> <Stores diffgr:id="Stores1" msdata:rowOrder="0" diffgr:hasChanges="modified"> <stor_id>999</stor_id> <stor_name>Eric the Read Books</stor_name> <stor_address>788 Catamaugus Ave.</stor_address> <city>Seattle</city> <state>WA</state> <zip>98056</zip> </Stores> <Stores diffgr:id="Stores3" msdata:rowOrder="2"> <stor_id>7067</stor_id> <stor_name>News & Brews</stor_name> <stor_address>577 First St.</stor_address> <city>Los Gatos</city> <state>CA</state> <zip>96745</zip> </Stores> <Stores diffgr:id="Stores4" msdata:rowOrder="3"> <stor_id>7131</stor_id> <stor_name>Doc-U-Mat: Quality Laundry and Books</stor_name> <stor_address>24-A Avogadro Way</stor_address> <city>Remulade</city> <state>WA</state> <zip>98014</zip> </Stores> <Stores diffgr:id="Stores5" msdata:rowOrder="4"> <stor_id>7896</stor_id> <stor_name>Fricative Bookshop</stor_name> <stor_address>89 Madison St.</stor_address> <city>Fremont</city> <state>CA</state> <zip>90019</zip> </Stores> <Stores diffgr:id="Stores6" msdata:rowOrder="5"> <stor_id>8042</stor_id> <stor_name>Bookbeat</stor_name> <stor_address>679 Carson St.</stor_address> <city>Portland</city> <state>OR</state> <zip>89076</zip> </Stores> <Stores diffgr:id="Stores7" msdata:rowOrder="6" diffgr:hasChanges="inserted"> <stor_name>New Store</stor_name> </Stores> </NewDataSet> <diffgr:before> <Stores diffgr:id="Stores1" msdata:rowOrder="0"> <stor_id>6380</stor_id> <stor_name>Eric the Read Books</stor_name> <stor_address>788 Catamaugus Ave.</stor_address> <city>Seattle</city> <state>WA</state> <zip>98056</zip> </Stores> <Stores diffgr:id="Stores2" msdata:rowOrder="1"> <stor_id>7066</stor_id> <stor_name>Barnum's</stor_name> <stor_address>567 Pasadena Ave.</stor_address> <city>Tustin</city> <state>CA</state> <zip>92789</zip> </Stores> </diffgr:before> </diffgr:diffgram> НА ЗАМЕТКУ В листинге 10.7 приведено содержимое файла DiffGram.xml, полученного в pезультате выполнения этого метода. Листинг 10.7. XML-файл changes.xml в формате DiffGram только с измененными записями<?xml version="1.0" standalone="yes"?> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <NewDataSet> <Stores diffgr:id="Stores1" msdata:rowOrder="0" diffgr:hasChanges="modified"> <stor_id>999</stor_fd> <stor_name>Eric the Read Books</stor_name> <stor_address>788 Catamaugus Ave.</stor_address> <city>Seattle</city> <state>WA</state> <zip>98056</zip> </Stores> <Stores diffgr:id="Stores3" msdata:rowOrder="2" diffgr:hasChanges="inserted"> <stor_name>New Store</stor_name> </Stores> </NewDataSet> <diffgr:before> <Stores diffgr:id="Stores1" msdata:rowOrder="0"> <stor_id>6380</stor_id> <stor_name>Eric the Read Books</stor_name> <stor_address>788 Catamaugus Ave.</stor_address> <city>Seattle</city> <state>WA</state> <zip>98056</zip> </Stores> <Stores diffgr:id="Stores2" msdata:rowOrder="1"> <stor_id>7066</stor_id> <stor_name>Barnum's</stor__name> <stor_address>567 Pasadena Ave.</stor_address> <city>Tustin</city> <state>CA</state> <zip>92789</zip> </Stores> </diffgr:before> </diffgr:diffgram> Бизнес-ситуация 10.1: подготовка XML-файлов для бизнес-партнеровКомпания Jones Novelty обменивается информацией с помощью электронных средств передачи данных со многими своими поставщиками и партнерами. Развитие этой тенденции, вероятно, приведет к тому, что компании придется спустя какое-то время применить качественно новое решение, например систему Microsoft BizTalk Server. В настоящее время Брэд Джонс стремится удовлетворить текущие потребности и сохранить конкурентоспособность, применяя XML для передачи транзакций. Для этого будут использованы уже описанные возможности XML и ряд других, которые описываются далее. Следует отметить, что многие требования можно удовлетворить даже без использования "мощных и тяжеловесных" платформ, инструментов и технологий, например XSLT. Сначала следует организовать отправку XML-файла с перечнем товаров на складах. Для этого должны быть посланы сведения из всех полей таблицы tblInventory, за исключением поля WholesalePrice. Хотя это можно организовать с помощью простого запроса, который включает все поля, кроме WholesalePrice, в данном примере используется способ на основе XML-свойств. Для создаваемого XML-файл существует еще одно требование: в него необходимо включить XSD-схему с описанием всех полей как элементов, за исключением поля ID, которое передается с помощью атрибута. Для создания этого приложения выполните перечисленные ниже действия. 1. Запустите интегрированную среду разработки Visual Studio .NET и создайте новый проект Visual Basic Windows Application. Для этого в диалоговом окне New Project (Новый проект) выберите тип проекта Visual Basic Project в области Project Types (Типы проектов), а затем шаблон Windows Application (Приложение Windows) в области Templates (Шаблоны). 2. Назовите проект BusinessCaseIO. 3. Укажите путь к файлам проекта. 4. Увеличьте размер формы Form1. 5. В окне свойств Properties укажите значение frmPrepareXML для свойства (Name) и значение Prepare XML для свойства Text формы Form1. 6. В верхнем левом углу формы создайте кнопку, перетаскивая ее из панели элементов управления. 7. В окне свойств Properties укажите значение btnInventory для свойства (Name) и значение Create Inventory XML для свойства Text этой кнопки. В верхней части файла введите следующий код: Imports System Imports System.Data Imports System.Data.SqlClient Затем в определении класса формы frmPrepareXML введите приведенный ниже код. Dim en As New SqlConnection _ ("data source=localhost;initial catalog=Novelty;user id=sa") Private Sub btnInventory_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnlnventory.Click Dim dsInventory As New DataSet() Dim daInventory As New SqlDataAdapter _ ("select * from tblInventory ", en) daInventory.Fill(dsInventory, "tblInventory") ' Сохранение поля ID как XML-атрибута, а не элемента dsInventory.Tables("tblInventory").Columns("ID").ColumnMapping = _ MappingType.Attribute ' Сокрытие поля WholesalePrice в сохраненном XML-файле dslnventory.Tables("tbllnventory").Columns _ ("WholesalePrice").ColumnMapping = MappingType.Hidden ' Сохранение данных в XML-файле, включая встроенную схему. dsInventory.WriteXml("..\Inventory.xml", XmlWriteMode.WriteSchema) End Sub После вставки данных в объект DataSet для формирования XML-файла используются следующие два выражение. Первое выражение указывает на то, что поле ID следует сохранить как XML-атрибут: dsInventory.Tables("tblInventory").Columns("ID").ColumnMapping = _ MappingType.Attribute Второе выражение указывает на сокрытие поля WholesalePrice в сохраненном XML-файле: dslnventory.Tables("tbllnventory").Columns _ ("WholesalePrice").ColumnMapping = MappingType.Hidden Наконец, во время сохранения данных используется второй параметр метода WriteXML, который указывает на необходимость включения XSD-схемы вместе с данными. Полученный в результате XML-файл показан в листинге 10.8. Листинг 10.8. Пример сохранения таблицы tblInventory в виде XML-файла<?xml version="1.0" standalone="yes"?> <NewDataSet> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="tblInventory"> <xs:complexType> <xs:sequence> <xs:element name="ProductName" type="xs:string" minOccurs="0" msdata:Ordinal="1" /> <xs:element name="RetailPrice" type="xs:decimal" minOccurs="0" msdata:Ordinal="3" /> <xs:element name="Description" type="xs:string" minOccurs="0" msdata:Ordinal="4" /> </xs:sequence> <xs:attribute name="ID" type="xs:int" /> <xs:attribute name="WholesalePrice" type="xs:decimal" use="prohibited" /> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <tblInventory ID="1"> <ProductName>Rubber Chicken</ProductName> <RetailPrice>2.99</RetailPrice> <Description>The quintessential rubber chicken.</Description> </tblInventory> <tblInventory ID="2"> <ProductName>Joy Buzzer</ProductName> <RetailPrice>9.99</RetailPrice> <Description>They will get a real shock out of this.</Description> </tblInventory> <tblInventory ID="3"> <ProductName>Seltzer Bottle</ProductName> <RetailPrice>15.24</RetailPrice> <Description>Seltzer sold separately.</Description> </tblInventory> <tblInventory ID="4"> <ProductName>Ant Farm</ProductName> <RetailPrice>14.99</RetailPrice> <Description>Watch ants where they live and breed.</Description> </tblInventory> <tblInventory ID="5"> <ProductName>Wind-Up Robot</ProductName> <RetailPrice>29.99</RetailPrice> <Description>Giant robot: attack toybox!</Description> </tblInventory> <tblInventory ID="6"> <ProductName>Rubber Eyeballs</ProductName> <RetailPrice>0.99</RetailPrice> <Description>Peek-a-boo!</Description> </tblInventory> <tblInventory ID="7"> <ProductName>Doggy Mess</ProductName> <RetailPrice>1.99</RetailPrice> <Description>Yechhh!</Description> </tblInventory> <tblInventory ID="8"> <ProductName>Mini-Camera</ProductName> <RetailPrice>9.99</RetailPrice> <Description>For future spies!</Description> </tblInventory> <tblInventory ID="9"> <ProductName>Glow Worms</ProductName> <RetailPrice>1.99</RetailPrice> <Description>Makes them easy to find</Description> </tblInventory> <tblInventory ID="10"> <ProductName>Insect Pops</ProductName> <RetailPrice>0.99</RetailPrice> <Description>Special treats</Description> </tblInventory> <tblInventory ID="11"> <ProductName>Alien Alarm Clock</ProductName> <RetailPrice>45.99</RetailPrice> <Description>Do you know what time it is out there?</Description> </tblInventory> <tblInventory ID="12"> <ProductName>Cinnamon Toothpicks</ProductName> <RetailPrice>1.99</RetailPrice> <Description>Really wakes up your mouth</Description> </tblInventory> </NewDataSet> Для составления ведомости на выдачу заработной платы сотрудникам компании нужно создать код сохранения информации о сотрудниках в формате XML для каждого отдела. Для этого разработчик базы данных должен включить в форму frmPrepareXML вторую кнопку btnEmployees и вставить в код класса формы frmPrepareXML код из листинга 10.9. Листинг 10.9. Код сохранения данных из таблиц tblEmployee и tblDepartment в XML-файлеPrivate Sub btnEmployees_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnEmployees.Click Dim dsEmployees As New DataSet() Dim daEmployees As New SqlDataAdapter _ ("select * from tblEmployee", en) Dim daDepartments As New SqlDataAdapter _ ("select * from tblDepartment", en) daDepartments.Fill(dsEmployees,"tblDepartment") daEmployees.Fill(dsEmployees, "tblEmployee") ' Определение отношения между таблицами. dsEmployees.Relations.Add("DepartmentEmployees", _ dsEmployees.Tables("tblDepartment").Columns("ID"), _ dsEmployees.Tables("tblEmployee").Columns("DepartmentID")) ' Сохранение данных в XML-файле. dsEmployees.WriteXml("..\Employees.xml") End Sub В этом коде для сохранения данных из таблиц tblDepartment и tblEmployee в XML-файле используются предлагаемые по умолчанию параметры объекта DataSet. Полученный в результате XML-файл Employees.xml показан в листинге 10.10. Листинг 10.10. XML-файл Employees. xml, полученный в результате сохранения данных из таблиц tblDepartment и tblEmployee<?xml version="1.0" standalone="yes"?> <NewDataSet> <tblDepartment> <ID>1</ID> <DepartmentName>Administration</DepartmentName> </tblDepartment> <tblDepartment> <ID>2</ID> <DepartmentName>Engineering</DepartmentName> </tblDepartment> <tblDepartment> <ID>3</ID> <DepartmentName>Sales</DepartmentName> </tblDepartment> <tblDepartment> <ID>4</ID> <DepartmentName>Marketing</DepartmentName> </tblDepartment> <tblEmployee> <ID>1</ID> <FirstName>Carole</FirstName> <LastName>Vermeren</LastName> <DepartmentID>2</DepartmentID> <Salary>222</Salary> </tblEmployee> <tblEmployee> <ID>2</ID> <FirstName>Cathy</FirstName> <LastName>Johnson</LastName> <DepartmentID>2</DepartmentID> <Salary>13000</Salary> </tblEmployee> <tblEmployee> <ID>3</ID> <FirstName>Eric</FirstName> <LastName>Haglund</LastName> <DepartmentID>4</DepartmentID> <Salary>12000</Salary> </tblEmployee> <tblEmployee> <ID>4</ID> <FirstName>Julie</FirstName> <LastName>Ryan</LastName> <DepartmentID>1</DepartmentID> <Salary>4000</Salary> </tblEmployee> <tblEmployee> <ID>5</ID> <FirstName>Richard</FirstName> <LastName>Halpin</LastName> <DepartmentID>2</DepartmentID> <Salary>10000</Salary> </tblEmployee> <tblEmployee> <ID>6</ID> <FirstName>Kathleen</FirstName> <LastName>Johnson</LastName> <DepartmentID>3</DepartmentID> <Salary>18000</Salary> </tblEmployee> <tblEmployee> <ID>7</ID> <FirstName>Sorel</FirstName> <LastName>Polito</LastName> <DepartmentID>4</DepartmentID> <Salary>28000</Salary> </tblEmployee> <tblEmployee> <ID>8</ID> <FirstName>Sorel</FirstName> <LastName>Terman</LastName> <DepartmentID>1</DepartmentID> <Salary>8000</Salary> </tblEmployee> <tblEmployee> <ID>9</ID> <FirstName>Randy</FirstName> <LastName>Hobaica</LastName> <DepartmentID>2</DepartmentID> <Salary>18000</Salary> </tblEmployee> <tblEmployee> <ID>10</ID> <FirstName>Matthew</FirstName> <LastName>Haglund</LastName> <DepartmentID>3</DepartmentID> <Salary>30000</Salary> </tblEmployee> <tblEmployee> <ID>11</ID> <FirstName>Cathy</FirstName> <LastName>Vermeren</LastName> <DepartmentID>4</DepartmentID> <Salary>0</Salary> </tblEmployee> <tblEmployee> <ID>12</ID> <FirstName>Brad</FirstName> <LastName>Townsend</LastName> <DepartmentID>2</DepartmentID> <Salary>12000</Salary> </tblEmployee> <tblEmployee> <ID>13</ID> <FirstName>Jennifer</FirstName> <LastName>Eves</LastName> <DepartmentID>2</DepartmentID> <Salary>26000</Salary> </tblEmployee> <tblEmployee> <ID>14</ID> <FirstName>Steve</FirstName> <LastName>Marshall</LastName> <DepartmentID>3</DepartmentID> <Salary>42000</Salary> </tblEmployee> <tblEmployee> <ID>15</ID> <FirstName>Laura</FirstName> <LastName>Davidson</LastName> <DepartmentID>4</DepartmentID> <Salary>60000</Salary> </tblEmployee> <tblEmployee> <ID>16</ID> <FirstName>Angela</FirstName> <LastName>Stefanac</LastName> <DepartmentID>2</DepartmentID> <Salary>16000</Salary> </tblEmployee> <tblEmployee> <ID>17</ID> <FirstName>Marjorie</FirstName> <LastName>Bassett</LastName> <DepartmentID>2</DepartmentID> <Salary>34000</Salary> </tblEmployee> <tblEmployee> <ID>18</ID> <FirstName>Joe</FirstName> <LastName>Chideya</LastName> <DepartmentID>3</DepartmentID> <Salary>54000</Salary> </tblEmployee> <tblEmployee> <ID>19</ID> <FirstName>Katie</FirstName> <LastName>Chideya</LastName> <DepartmentID>4</DepartmentID> <Salary>76000</Salary> </tblEmployee> <tblEmployee> <ID>20</ID> <FirstName>Terri</FirstName> <LastName>Allen</LastName> <DepartmentID>1</DepartmentID> <Salary>20000</Salary> </tblEmployee> <tblEmployee> <ID>21</ID> <FirstName>Mike</FirstName> <LastName>Doberstein</LastName> <DepartmentID>2</DepartmentID> <Salary>42000</Salary> </tblEmployee> <tblEmployee> <ID>22</ID> <FirstName>Terri</FirstName> <LastName>Woodruff</LastName> <DepartmentID>3</DepartmentID> <Salary>66000</Salary> </tblEmployee> <tblEmployee> <ID>23</ID> <FirstName>Cathy</FirstName> <LastName>Rosenthal</LastName> <DepartmentID>4</DepartmentID> <Salary>0</Salary> </tblEmployee> <tblEmployee> <ID>24</ID> <FirstName>Margaret</FirstName> <LastName>Eves</LastName> <DepartmentID>1</DepartmentID> <Salary>24000</Salary> </tblEmployee> <tblEmployee> <ID>25</ID> <FirstName>Mikki</FirstName> <LastName>Lemay</LastName> <DepartmentID>2</DepartmentID> <Salary>50000</Salary> </tblEmployee> <tblEmployee> <ID>26</ID> <FirstName>Randy</FirstName> <LastName>Nelson</LastName> <DepartmentID>3</DepartmentID> <Salary>78000</Salary> </tblEmployee> <tblEmployee> <ID>27</ID> <FirstName>Kathleen</FirstName> <LastName>Husbands</LastName> <DepartmentID>4</DepartmentID> <Salary>108000</Salary> </tblEmployee> <tblEmployee> <ID>28</ID> <FirstName>Kathleen</FirstName> <LastName>Eberman</LastName> <DepartmentID>1</DepartmentID> <Salary>28000</Salary> </tblEmployee> <tblEmployee> <ID>29</ID> <FirstName>Richard</FirstName> <LastName>Rosenthal</LastName> <DepartmentID>2</DepartmentID> <Salary>58000</Salary> </tblEmployee> <tblEmployee> <ID>30</ID> <FirstName>Mike</FirstName> <LastName>Woodruff</LastName> <DepartmentID>3</DepartmentID> <Salary>90000</Salary> </tblEmployee> </NewDataSet> К сожалению, данный XML-файл содержит список сотрудников, который не сгруппирован по отделам. Несмотря на созданное отношение между родительской таблицей tblDepartment и дочерней таблицей tblEmployee полученный XML-файл содержит данные отдельно для каждой таблицы. Для вложения дочерних элементов из таблицы tblEmployee в родительские элементы из таблицы tblDepartment нужно указать значение True для свойства Nested объекта-отношения Relation. dsEmployees.Relations("DepartmentEmployees").Nested = True После вставки этой строки кода перед строкой сохранения данных dsInventory.WriteXml("..\Inventory.xml", XmlWriteMode.WriteSchema) будет получен XML-файл Employees.xml, показанный в листинге 10.11. Листинг 10.11. XML-файл Employees.xml с вложением дочерних элементов из таблицы tblEmployee в родительские элементы из таблицы tblDepartment<?xml version="1.0" standalone="yes"?> <NewDataSet> <tblDepartment> <ID>1</ID> <DepartmentName>Administration</DepartmentName> <tblEmployee> <ID>2035</ID> <FirstName>Julie</FirstName> <LastName>Ryan</LastName> <DepartmentID>1</DepartmentID> <Salary>4000</Salary> </tblEmployee> <tblEmployee> <ID>2039</ID> <FirstName>Sorel</FirstName> <LastName>Terman</LastName> <DepartmentID>1</DepartmentID> <Salary>8000</Salary> </tblEmployee> <tblEmployee> <ID>2051</ID> <FirstName>Terri</FirstName> <LastName>Allen</LastName> <DepartmentID>1</DepartmentID> <Salary>20000</Salary> </tblEmployee> <tblEmployee> <ID>2055</ID> <FirstName>Margaret</FirstName> <LastName>Eves</LastName> <DepartmentID>1</DepartmentID> <Salary>24000</Salary> </tblEmployee> <tblEmployee> <ID>2059</ID> <FirstName>Kathleen</FirstName> <LastName>Eberman</LastName> <DepartmentID>1</DepartmentID> <Salary>28000</Salary> </tblEmployee> </tblDepartment> <tblDepartment> <ID>2</ID> <DepartmentName>Engineering</DepartmentName> <tblEmployee> <ID>2032</ID> <FirstName>Carole</FirstName> <LastName>Vermeren</LastName> <DepartmentID>2</DepartmentID> <Salary>222</Salary> </tblEmployee> <tblEmployee> <ID>2033</ID> <FirstName>Cathy</FirstName> <LastName>Johnson</LastName> <DepartmentID>2</DepartmentID> <Salary>13000</Salary> </tblEmployee> <tblEmployee> <ID>2036</ID> <FirstName>Richard</FirstName> <LastName>Halpin</LastName> <DepartmentID>2</DepartmentID> <Salary>10000</Salary> </tblEmployee> <tblEmployee> <ID>2040</ID> <FirstName>Randy</FirstName> <LastName>Hobaica</LastName> <DepartmentID>2</DepartmentID> <Salary>18000</Salary> </tblEmployee> <tblEmployee> <ID>2043</ID> <FirstName>Brad</FirstName> <LastName>Townsend</LastName> <DepartmentID>2</DepartmentID> <Salary>12000</Salary> </tblEmployee> <tblEmployee> <ID>2044</ID> <FirstName>Jennifer</FirstName> <LastName>Eves</LastName> <DepartmentID>2</DepartmentID> <Salary>26000</Salary> </tblEmployee> <tblEmployee> <ID>204V</ID> <FirstName>Angela</FirstName> <LastName>Stefanac</LastName> <DepartmentID>2</DepartmentID> <Salary>16000</Salary> </tblEmployee> <tblEmployee> <ID>2048</ID> <FirstName>Marjorie</FirstName> <LastName>Bassett</LastName> <DepartmentID>2</DepartmentID> <Salary>34000</Salary> </tblEmployee> <tblEmployee> <ID>2052</ID> <FirstName>Mike</FirstName> <LastName>Doberstein</LastName> <DepartmentID>2</DepartmentID> <Salary>42000</Salary> </tblEmployee> <tblEmployee> <ID>2056</ID> <FirstName>Mikki</FirstName> <LastName>Lemay</LastName> <DepartmentID>2</DepartmentID> <Salary>50000</Salary> </tblEmployee> <tblEmployee> <ID>2060</ID> <FirstName>Richard</FirstName> <LastName>Rosenthal</LastName> <DepartmentID>2</DepartmentID> <Salary>58000</Salary> </tblEmployee> </tblDepartment> <tblDepartment> <ID>3</ID> <DepartmentName>Sales</DepartmentName> <tblEmployee> <ID>2037</ID> <FirstName>Kathleen</FirstName> <LastName>Johnson</LastName> <DepartmentID>3</DepartmentID> <Salary>18000</Salary> </tblEmployee> <tblEmployee> <ID>2041</ID> <FirstName>Matthew</FirstName> <LastName>Haglund</LastName> <DepartmentID>3</DepartmentID> <Salary>30000</Salary> </tblEmployee> <tblEmployee> <ID>2045</ID> <FirstName>Steve</FirstName> <LastName>Marshall</LastName> <DepartmentID>3</DepartmentID> <Salary>42000</Salary> </tblEmployee> <tblEmployee> <ID>2049</ID> <FirstName>Joe</FirstName> <LastName>Chideya</LastName> <DepartmentID>3</DepartmentID> <Salary>54000</Salary> </tblEmployee> <tblEmployee> <ID>2053</ID> <FirstName>Terri</FirstName> <LastName>Woodruff</LastName> <DepartmentID>3</DepartmentID> <Salary>66000</Salary> </tblEmployee> <tblEmployee> <ID>2057</ID> <FirstName>Randy</FirstName> <LastName>Nelson</LastName> <DepartmentID>3</DepartmentID> <Salary>78000</Salary> </tblEmployee> <tblEmployee> <ID>2061</ID> <FirstName>Mike</FirstName> <LastName>Woodruff</LastName> <DepartmentID>3</DepartmentID> <Salary>90000</Salary> </tblEmployee> </tblDepartment> <tblDepartment> <ID>4</ID> <DepartmentName>Marketing</DepartmentName> <tblEmployee> <ID>2034</ID> <FirstName>Eric</FirstName> <LastName >Haglund</LastName> <DepartmentID>4</DepartmentID> <Salary>12000</Salary> </tblEmployee> <tblEmployee> <ID>2038</ID> <FirstName>Sorel</FirstName> <LastName>Polito</LastName> <DepartmentID>4</DepartmentID> <Salary>28000</Salary> </tblEmployee> <tblEmployee> <ID>2042</ID> <FirstName>Cathy</FirstName> <LastName>Vermeren</LastName> <DepartmentID>4</DepartmentID> <Salary>0</Salary> </tblEmployee> <tblEmployee> <ID>2046</ID> <FirstName>Laura</FirstName> <LastName>Davidson</LastName> <DepartmentID>4</DepartmentID> <Salary>60000</Salary> </tblEmployee> <tblEmployee> <ID>2050</ID> <FirstName>Katie</FirstName> <LastName>Chideya</LastName> <DepartmentID>4</DepartmentID> <Salary>76000</Salary> </tblEmployee> <tblEmployee> <ID>2054</ID> <FirstName>Cathy</FirstName> <LastName>Rosenthal</LastName> <DepartmentID>4</DepartmentID> <Salary>5555</Salary> </tblEmployee> <tblEmployee> <ID>2058</ID> <FirstName>Kathleen</FirstName> <LastName>Husbands</LastName> <DepartmentID>4</DepartmentID> <Salary>108000</Salary> </tblEmployee> </tblDepartment> </NewDataSet> Создание объекта XmlReader с помощью объекта CommandВ главе 4, "Модель ADO.NET: провайдеры данных", описываются способы работы с объектом Command, который является ключевым объектом — провайдером данных на платформе .NET. В ней рассматриваются способы выполнения команд на основе объектов ExecuteReader, ExecuteScalar и ExecuteNonQuery. Хотя все провайдеры данных на платформе .NET реализуют эти методы, объект SqlCommand имеет дополнительный метод ExecuteXmlReader, который используется для извлечения и доступа к XML-данным из СУБД SQL Server. Метод ExecuteXmlReader возвращает объект XmlReader точно так же, как он возвращает объект DataReader. Для демонстрации применения метода ExecuteXmlReader вернитесь к проекту ADO-XML и выполните следующее. 1. Включите в форму frmXML под кнопкой Write XML еще одну кнопку, перетаскивая ее из панели элементов управления. 2. В окне свойств Properties укажите значение btnExecuteXML для свойства (Name) и значение ExecuteXMLReader для свойства Text этой кнопки. 3. Затем в определении класса формы frmXML введите код из листинга 10.12. Листинг 10.12. Код извлечения и обработки данных из СУБД SQL Server в формате XMLPrivate Sub btnExecuteXML_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnExecuteXML.Click Dim cn As New SqlConnection _ ("data source=localhost;initial catalog=pubs;user id=sa") Dim cmd As New SqlCommand _ ("select * from stores for xml auto, elements", en) Dim reader As Xml.XmlReader Dim str As New System.Text.StringBuilder() cn.Open() ' Выполнение SQL-команды Select с предложением FOR XML. reader = cmd.ExecuteXmlReader() ' Поиск и извлечение данных из узлов-элементов. While reader.Read() Select Case reader.NodeType Case Xml.XmlNodeType.Element str.Append("<" & reader.Name & ">") Case Xml.XmlNodeType.EndElement str.Append("</" & reader.Name & ">" & ControlChars.CrLf) Case Xml.XmlNodeType.Text str.Append(reader.Value) Case Else ' В данном примере игнорируется. End Select End While MsgBox(str.ToString) сn.Close() End Sub Код в листинге 10.12 содержит пример упрощенного использования метода ЕхеcuteXmlReader в котором просто отображаются данные (вместе с дескрипторами) из таблицы базы данных pubs. СУБД SQL Server передается показанная ниже SQL-команда Select, в которой явно указаны возвращаемые поля в виде XML-элементов. "select * from stores for xml auto, elements" В таком случае обработка разных типов XML-узлов упрощается, потому что достаточно найти только начальный и конечный узлы, а текстовые узлы между ними будут содержать фактические данные. Более надежная обработка XML-документа основана на конструкции Select Case, в которой учтены узлы всех типов. После щелчка на кнопке ExecuteXMLReader будет выполнен код из листинга 10.12 и на экране появится диалоговое окно, которое показано на рис. 10.2. РИС. 10.2. Диалоговое окно с XML-данными, извлеченными из СУБД SQL Server Объект XmlDataDocumentВ главе 9, "XML и .NET", рассматривается объект XmlDataDocument и способы его использования для доступа к иерархическим данным в виде узлов загруженного в оперативную память XML-документа. В этой книге также рассматриваются способы извлечения реляционных данных (и доступа к ним) из традиционной SQL-совеместимой базы данных. При этом необходимо выяснить следующее: • как быть, если данные поступили из XML-источника, а нам известны только реляционные способы навигации и манипуляции записями; • и наоборот: как быть, если данные поступили из SQL-совместимой базы данных, а нам известны только XML-совместимые способы навигации и манипуляции записями. Ответы на эти простые вопросы основаны на применении объекта XmlDataDocument. Он является производным от класса XmlDocument, но обладает расширенными возможностями. Помимо внутренней копии данных, он содержит XML-совместимые средства доступа к ним как к классу XmlDocument с помощью XML-узлов, а также реляционные средства доступа на основе объекта DataSet. Объект XmlDataDocument автоматически синхронизирует оба эти представления (или, иначе говоря, способа доступа) таким образом, чтобы любые изменения, выраженные в одной технологии, сразу же отображались средствами другой технологии. Такой подход позволяет легко смешивать и находить соответствие между разными источниками данных на основе разных технологий. Для демонстрации этих средств вернитесь к проекту ADO-XML и выполните перечисленные ниже действия. 1. Вставьте еще две кнопки в форму frmXML сразу под кнопкой ExecuteXMLReader, перетаскивая их из панели элементов управления. 2. В окне свойств Properties укажите значение btnNavigateSQL для свойства (Name) и значение Navigate SQL для свойства Text первой кнопки. 3. В окне свойств Properties укажите значение btnAddRows для свойства (Name) и значение Add Rows to XML для свойства Text второй кнопки. 4. Для импорта пространства имен XPath включите строку кода Imports System.Xml.XPath в конце списка команд импорта в верхней части файла с кодом. 5. В код класса frmXML включите две подпрограммы. Private Sub btnNavigateSQL_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnNavigateSQL.Click Dim en As New SqlConnection _ ("data source=localhost;initial catalog=pubs;user id=sa") Dim da As New SqlDataAdapter("Select * from authors", cn) Dim ds As New DataSet() ' Вставка в объект DataSet данных из реляционной базы данных da.Fill(ds, "authors") ' Создание объекта XmlDataDocument на основе существующего ' объекта DataSet. Dim xmlDoc As New Xml.XmlDataDocument(ds) ' Получение объекта-навигатора из XmlDataDocument. Dim xmlNav As XPathNavigator = xmlDoc.CreateNavigator() ' Извлечение всех фамилий авторов из штата Калифорния (СА). Dim xIterator As XPathNodeIterator xIterator = _ xmlNav.Select("//authors[state='CA']/au_lname") ' Последовательный обход всех выбранных узлов и ' отображение фамилий всех авторов. Dim str As New System.Text.StringBuilder() While (xIterator.MoveNext()) str.Append(xIterator.Current.Value & ControlChars.CrLf) End While MsgBox(str.ToString) End Sub Private Sub btnAddRows_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAddRows.Click Dim dsPubs As New DataSet() ' Считывание XML-данных из файла. dsPubs.ReadXml("..\Pubs.xml") ' Вставка новой записи. Dim row As DataRow = dsPubs.Tables("Publishers").NewRow() row("pub_name") = "Newbie Publishing Corp." row("city") = "New York" row("state") = "NY" row("Country") = "USA" dsPubs.Tables("Publishers").Rows.Add(row) ' Связывание объекта DataSet с сеткой Data Grid ' для просмотра новых данных. grdData.DataMember = "publishers" grdData.DataSource = dsPubs End Sub Подпрограмма btnNavigateSQL_Click считывает данные из базы данных SQL Server, а затем выполняет обход всех записей, извлеченных с помощью XPATH-запроса. В этой подпрограмме ключевыми являются приведенные ниже строки. Dim xmlDoc As New Xml.XmlDataDocument(ds) ' Получение объекта-навигатора из XmlDataDocument. Dim xmlNav As XPathNavigator = xmlDoc.CreateNavigator() ' Извлечение всех фамилий авторов из штата Калифорния (CA). Dim xIterator As XPathNodeIterator xIterator = _ xmlNav.Select("//authors[state='CA']/au_lname") Сначала объект DataSet с данными связывается с новым объектом XmlDataDocument. Затем создается объект-навигатор XPathNavigator на основе объекта-документа XmlDataDocument. После чего на основе объекта XPathNavigator создается объект-итератор XPathNodeIterator. Далее строка XPATH-запроса передается методу Select для возвращения списка фамилий авторов (т.е. значений поля из Калифорнии (т.е. у которых поле state имеет значение СА). После этого выполняется последовательный обход всех узлов, извлеченных данным запросом, и создается строка с искомым перечнем авторов. Эта строка отображается в диалоговом окне, которое показано на рис. 10.3. РИС. 10.3. Диалоговое окно с XML-данными, извлеченными из объекта DataSet Вторая подпрограмма, btnAddRows_Clicks, выполняет другую задачу. Сначала она считывает XML-данные с помощью метода ReadXml из файла Pubs. в набор данных dsPubs, как показано в листинге 10.1. Этот метод автоматически создает таблицу publishers в объекте DataSet. Далее новые данные вставляются с помощью реляционных методов и объектов, например объекта-записи DataRow. Новый объект DataRow включается в схему таблицы publishers, а полям присваиваются указанные значения. После этого новая запись вставляется в таблицу publishers, а результат вставки отображается в сетке DataGrid (рис. 10.4). РИС. 10.4. Вид сетки DataGrid после считывания данных из XML-файла вставки строки РезюмеВ этой главе демонстрируется тесная взаимосвязь и интеграция способов доступа к данным и XML на платформе .NET Framework. В частности, показано, что объект DataSet обладает возможностями чтения и записи XML-данных и XML-схем. При отсутствии определения XML-схемы объект DataSet способен вывести его на основании анализа структуры данных в считанном XML-документе. С другой стороны, объект XmlDataDocument образует мост между реляционным и иерархическим миром XML. Доступ к данным внутри объекта XmlDataDocument можно получить либо XML-совместимым способом, либо реляционным. Изменения в одном представлении автоматически реплицируются в другом представлении. Разработчик базы данных может выбрать наиболее удобный способ доступа к данным и манипулирования ими. Методам и инструментам реляционного и иерархического доступа к данным посвящено множество специализированных книг и учебных пособий. Невозможно в рамках одной главы или даже целой книги полностью описать их. Здесь следует лишь запомнить, что ADO.NET и XML-объекты на платформе .NET предназначены для наиболее тесной интеграции и взаимодействия друг с другом. Вопросы и ответыИногда в документации по платформе.NET, помимо XSD-формата схемы данных, упоминается XDR-формат. Что это такое? XSD-формат — это стандартный формат определения схемы XML-данных, принятый консорциумом World Wide Web Consortium (W3C), который специализируется на создании Web-ориентированных стандартов (более подробную информацию об этом консорциуме можно найти по адресу: www.w3c.org). Еще до окончания работ по созданию стандарта для XSD-формата компания Microsoft решила создать собственный временный формат XML-Data Reduced (XDR) для определений XML-схем. После завершения работы над стандартом XSD-формата в мае 2001 года Microsoft перешла к полной поддержке XSD-формата. Несмотря на то что на платформе .NET Framework схемы данных сохраняются только в XSD-формате, они могут считываться в обоих форматах для совместимости с прежними унаследованными системами. В наборе инструментальных средств разработчика .NET Framework SDK предусмотрена специальная утилита xsd.exe, которая может (помимо прочего) конвертировать схему данных из формата XDR в формат XSD. Как конкретно ADO.NET автоматически определяет схему данных после анализа XML-документа? Алгоритм автоматического определения схемы данных хорошо документирован в справочных материалах Visual Studio .NET. Для ознакомления с ним следует обратиться к разделу Inferring DataSet Relational Structure from XML (Автоматическое определение XML-схемы данных после анализа реляционной структуры объекта DataSet). В нем приводится краткое описание алгоритма, некоторые особенности анализа таблиц, полей и отношений, а также ограничения алгоритма. В этой главе описаны два способа доступа к данным: реляционный на основе объекта DataSet и иерархический на основе XmlDataDocument. В каких ситуациях следует их применять? Вообще говоря, не существует единственно верного и универсального способа. Каждый из них следует применять в зависимости от используемых источников данных и поставленной задачи. Платформа .NET Framework позволяет гибко использовать данные из любых источников: реляционных или иерархических. Независимо от источника, данные можно сохранять как реляционные или как иерархические в соответствии с конкретными потребностями. Кроме того, если источник данных и полученные после обработки данные должны иметь формат XML, а вы в недостаточной степени владеете технологиями и инструментами XML, то поставленную задачу все равно можно успешно выполнить с помощью реляционных инструментов на основе объектов DataSet и DataTable. |
|
||||||||||||||||||||||
Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Наверх |
||||||||||||||||||||||||
|