Провайдер 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.
|