XML в MS SQL Server 2000 и технологиях доступа к данным Страница 6. FOR XML на стороне клиента
|
Страница 6 из 15
FOR XML на стороне клиента Провайдер SQLXMLOLEDB является типичным сервисным провайдером, как уже упоминавшиеся ранее MSDataShape и MSPersist, в том плане, что он получает данные от другого провайдера, а не непосредственно из источника. SQLXMLOLEDB позволяет преобразовывать recordset в XML непосредственно на клиенте. Таким образом, провайдер SQLOLEDB, стоящий между SQLXMLOLEDB и SQL Server, получает от сервера не XML-поток, а обычный recordset и передает его SQLXMLOLEDB, который уже занимается превращением реляционной информации в XML. Скрипт 5 демонстрирует FOR XML на стороне клиента. public static void Execute_FORXMLQuery_OnClient() { ... cmd.CommandText = "SELECT c.ContactName, COUNT(o.OrderDate) as 'Кол-во заказов' FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID WHERE o.OrderDate between ? and ? GROUP BY c.ContactName FOR XML NESTED"; cmd.CreateParameter().Value = "19970101"; cmd.CreateParameter().Value = "19971231 23:59:59"; cmd.ClientSideXml = true; cmd.OutputEncoding = "UTF-8"; cmd.RootTag = "Корень"; Stream str = cmd.ExecuteStream(); StreamReader sr = new StreamReader(str); FileInfo f = new FileInfo("..\\Results\\FORXMLQueryResults.xml"); StreamWriter sw = new StreamWriter(f.FullName, false, System.Text.Encoding.UTF8); sw.WriteLine("<!--Этот XML сделан на стороне клиента-->"); str.Position = 0; sw.Write(sr.ReadToEnd()); sr.Close(); sw.Close(); ... } Скрипт 5 При помощи SQL Profiler можно оттрассировать и сравнить запросы, которые в действительности обрабатываются сервером при выполнении Скриптов 4 и 5. Скрипт 4: exec sp_executesql N'SELECT '''' SELECT c.ContactName, c.ContactTitle, o.OrderDate FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID WHERE c.ContactName = @P1 AND year(o.OrderDate) = @P2 FOR XML AUTO SELECT ''''', N'@P1 nvarchar(30),@P2 int', N'Maria Larsson', 1997 Скрипт 5: exec sp_executesql N'SELECT c.ContactName, COUNT(o.OrderDate) as ''Кол-во заказов'' FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID WHERE o.OrderDate between @P1 and @P2 GROUP BY c.ContactName ', N'@P1 nvarchar(8),@P2 nvarchar(17)', N'19970101', N'19971231 23:59:59' В Скрипте 5 я слегка изменил текст запроса, чтобы показать использование GROUP BY (этот предикат не разрешается в серверных FOR XML-запросах). Запрос считает количество заказов, сделанных каждым клиентом за определенный период времени. Обратите внимание на отсутствие предиката FOR XML во втором случае. Это значит, что преобразование recordset'a в XML действительно происходит в данном случае на клиенте. Несмотря на бОльшие издержки на стороне клиента такая схема работы является более универсальной и позволяет получать клиенту XML от тех источников данных, которые его не поддерживают и не будут. Для этого будет достаточно в строке соединения: "Provider= SQLXMLOLEDB;DataProvider=SQLOLEDB, …" поставить вместо SQL Server соответствующего OLE DB-провайдера. К сожалению, для этого придется подождать следующего, 4-го, веб-релиза. Пока SQLXMLOLEDB умеет работать только с SQL Server 2000. При клиентском XML-форматировании не поддерживается возврат в качестве результата одной команды нескольких recordset'ов, зато допускается предикат GROUP BY с агрегатными функциями. Режим FOR XML NESTED клиентского форматирования примерно соответствует FOR XML AUTO серверного, за исключением того, что вместо псевдонимов в имена элементов ставятся настоящие названия таблиц. О других различиях можно прочитать в документации на SQLXML 3.0. |