Введення в SQL Server Analysis Services для розробника. CommandText і CommandStream., Інші СУБД, Бази даних, статті

Виконання довільного XMLA засобами ADOMD.NET є привабливим, але, на жаль, недосяжним рішенням незважаючи на те, що в Інтернеті можна натрапити на людей, які стверджують, що їм вдалося його досягти тими чи іншими засобами. Подекуди мимохідь згадується (Не буду показувати пальцем на MSDNовскій блог одного шановного товариша), що все, що для цього потрібно – це засунути текст XMLA-запиту не в CommandText, а в CommandStream об’єкта AdomdCommand і виконати ExecuteXmlReader(). На жаль, це фікція. Документація на ADOMD обклала розробників досить щільно, не залишивши в тому числі лазівки у вигляді CommandStream. В російської MSDN Library на цю тему, до речі, на чистому російською мовою йдеться: “The AdomdCommand assumes that the System.IO.Stream contains an XML for Analysis compliant command (that is, a command that can be framed by the <Command> tag within an XML for Analysis request)”. Виділено мною. Іншими словами, що CommandStream, як і CommandText, з усього тексту XMLA-запиту сприймає тільки начинку елемента Command і сам за сценою загортає її в належні батьківські елементи. Спроба засунути в нього повноцінний XMLA, наприклад, з параметрами у вигляді елемента – див Скрипт 1 попереднього поста – призводить до тієї ж помилку, що і в разі CommandText – Див Скрипт 4 позапредидущего поста.

using System.Data;

using System.IO;

using System.Xml;

using System.Diagnostics;

using Microsoft.AnalysisServices.AdomdClient;

using System.Text;

class Program

{

    static void Main(string[] args)

    {

        AdomdConnection cnn = new AdomdConnection(@”Data Source=http://192.168.0.136/msolap/msmdpump.dll; User ID=192.168.0.136Administrator;Password=Abra_Chupakabra”);

        cnn.Open();

        string xmla = @”<Execute xmlns=”urn:schemas-microsoft-com:xml-analysis”>

                           <Command>

                               <Statement>

                                   select [Measures].members on 0,

                                   Filter(Customer.[Customer Geography].Country.members,

                                   Customer.[Customer Geography].CurrentMember.Name = @CountryName) on 1

                                   from [Adventure Works]

                               </Statement>

                           </Command>

                           <Properties>

                               <PropertyList>

                                   <Catalog>Adventure Works DW 2008R2</Catalog>

                               </PropertyList>

                           </Properties>

                           <Parameters>

                               <Parameter>

                                   <Name>CountryName</Name>

                                   <Value>”United Kingdom”</Value>

                               </Parameter>

                           </Parameters>

                      </Execute>”;

        AdomdCommand cmd = new AdomdCommand();

        cmd.Connection = cnn;

        cmd.CommandStream = new MemoryStream(Encoding.UTF8.GetBytes(xmla));

        XmlReader res = cmd.ExecuteXmlReader();

        res.MoveToContent(); res.Read();

        Debug.WriteLine(res.ReadOuterXml());

        res.Close();

        cnn.Close();

    }

}

Скрипт 1

Рис.1

Щоб цей код заробив, запит в CommandStream треба переписати подібно Скрипту 2 з попереднього поста, взявши тільки начинку елемента Command і засунувши елементи Properties і Parameters у відповідні властивості об’єкта AdomdCommand. Тег також можна опускати, як ми пам’ятаємо. Якщо всередині CommandText (Або, відповідно, CommandStream) Немає ніяких тегів, ADO MD за замовчуванням обертає вміст тегом static void Main(string[] args)

    {

       AdomdConnection cnn = new AdomdConnection(“Data Source=http://192.168.0.136/msolap/msmdpump.dll;” +

                                                 “User ID=192.168.0.136Administrator;Password=Abra_Chupakabra”);

       cnn.Open();

       string xmla = @”<Statement>

                          select [Measures].members on 0,

                                 Filter(Customer.[Customer Geography].Country.members,

                                        Customer.[Customer Geography].CurrentMember.Name = @CountryName) on 1

                          from [Adventure Works]

                      </Statement>”;

           

       AdomdCommand cmd = new AdomdCommand();

       cmd.Connection = cnn;

       cmd.CommandStream = new MemoryStream(Encoding.UTF8.GetBytes(xmla));

       cmd.Properties.Add(“Catalog”, “Adventure Works DW 2008R2”);

       cmd.Parameters.Add(new AdomdParameter(“CountryName”, “United Kingdom”));

       XmlReader res = cmd.ExecuteXmlReader();

       res.MoveToContent(); res.Read();

       string s = res.ReadOuterXml();

       res.Close(); cnn.Close();

    }

Скрипт 2

Рис.2

Метод ExecuteXmlReader повертає результат у вигляді XML, як якщо б ми виконували XMLA-Запит з SSMS.

Передача тексту команди у властивості CommandText або CommandStream ніяк не впливає на формат передачі результату. Якщо результатом команди є селлсет, його можна отримати як у вигляді XML за допомогою методу ExecuteXmlReader, як ми тільки що бачили в скрипті 2, так і у вигляді об’єкта CellSet за допомогою методу ExecuteCellSet:

static void Main(string[] args)

    {

       AdomdConnection cnn = new AdomdConnection(“Data Source=http://192.168.0.136/msolap/msmdpump.dll;” +

                                                 “User ID=192.168.0.136Administrator; Password=Abra_Chupakabra”);

       cnn.Open();

       string xmla = @”<Statement>

                          select [Measures].members on 0,

                                 Filter(Customer.[Customer Geography].Country.members,

                                        Customer.[Customer Geography].CurrentMember.Name = @CountryName) on 1

                          from [Adventure Works]

                      </Statement>”;

           

       AdomdCommand cmd = new AdomdCommand();

       cmd.Connection = cnn;

       cmd.CommandStream = new MemoryStream(Encoding.UTF8.GetBytes(xmla));

       cmd.Properties.Add(“Catalog”, “Adventure Works DW 2008R2”);

       cmd.Parameters.Add(new AdomdParameter(“CountryName”, “United Kingdom”));

       CellSet res = cmd.ExecuteCellSet();

       for (int i = 0; i < res.Axes[0].Positions.Count; i++)

       {

           Debug.WriteLine(“”);

           for (int j = 0; j < res.Axes[1].Positions.Count; j++)

               Debug.Write(res.Cells[i, j].FormattedValue);

       }

       cnn.Close();

    }

Скрипт 3


Я скомбінував в цьому прикладі першу половину з скриптів 2, а другу, яка CellSet, – з скриптів 2 попереднього поста. Натурально, виходить те ж саме, що і на рис.3 попереднього поста.

Якщо команда не є запитом, що повертає шматок кубика, очевидно, що бестолку просити її при цьому повернути селлсет – буде помилка. Наприклад, якщо в попередній скрипт замість Селекта підставити XMLA-Команду процесингу

<Batch xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine”>

  <Parallel>

    <Process xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:ddl2=”http://schemas.microsoft.com/analysisservices/2003/engine/2″ xmlns:ddl2_2=”http://schemas.microsoft.com/analysisservices/2003/engine/2/2″ xmlns:ddl100_100=”http://schemas.microsoft.com/analysisservices/2008/engine/100/100″>

      <Object>

        <DatabaseID>Adventure Works DW 2008 R2</DatabaseID>

        <DimensionID>Dim Product</DimensionID>

      </Object>

      <Type>ProcessUpdate</Type>

    </Process>

  </Parallel>

</Batch>

Скрипт 4

при спробі повернути результат трапиться помилка:

Pіс.3

У той же час якщо Скрипт 4 в якості тексту команди підставити в Скрипт 2, то за допомогою методу ExecuteXmlReader цей запит нормально виконується, повертаючи результат

<root xmlns=”urn:schemas-microsoft-com:xml-analysis:empty” />:

Рис.4

Це те, що з’являється в SSMS в панелі Results. Є ще цікаве питання, як зловити те, що з’являється в панелі Messages, але я поки не буду на нього відволікатися, тому що робиться це нетривіально і абсолютно не так, як в SQL Server.
До слова сказати, (а також ) є такою ж командою XMLA, тобто може стояти під елементом , Як і – Див http://msdn.microsoft.com/en-us/library/ms187139.aspx, отже, може виступати в якості AdomdCommand.

Виникає питання: навіщо паралельно до CommandText “у знадобилося мати ще властивість CommandStream, якщо ідейно у них однакові обмеження? Мабуть, CommandStream передбачається використовувати, якщо вміст досить велика і зберігається у файлі. Особливо цим відрізняються DDL-команди. Зайдіть в SSMS -> Object Explorer, клацніть правою кнопкою по кубу Adventure Works і скажіть Script Cube As -> Create.

Рис.5

Не повторюйте це на навантаженої машині. Процес генерації скрипта цілком по кубу досить задумливий. На його виході народжується здорова файл XML. Зрозуміло, що якщо його потрібно накотити з користувальницького додатка десь на іншій машині, щоб відтворити за структурою кубик Adventure Works, краще виконувати його через CommandStream.

    static void Main(string[] args)

    {

       AdomdConnection cnn = new AdomdConnection(“Data Source=http://192.168.0.136/msolap/msmdpump.dll;” +

                                                 “User ID=192.168.0.136Administrator; Password=Abra_Chupakabra”);

       cnn.Open();

       AdomdCommand cmd = new AdomdCommand();

       cmd.Connection = cnn;

       cmd.CommandStream = new FileStream(@”c:TempAdventureWorks.xmla”, FileMode.Open, FileAccess.Read);

       XmlReader res = cmd.ExecuteXmlReader();

       res.MoveToContent(); res.Read();

       Debug.WriteLine(res.ReadOuterXml());

       res.Close(); cnn.Close();

    }

Скрипт 5

 

Далі буде.


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*