Введение в SQL Server Analysis Services для разработчика. Discover из ADOMD.NET

Содержание предыдущей серии.

Средствами ADOMD.NET XMLA-запросы с методом Discover выполнять немного хитрее, чем Execute. Если ничтоже сумняшеся забабахать запрос из поста Метод Discover\Скрипт 1 в в AdomdCommand по аналогии, например, со Скриптом 2 поста про MDX-запросы, произойдет ошибка

class Program 
{ 
    static void Main(string[] args) 
    { 
        AdomdConnection cnn = new AdomdConnection("Data Source=localhost"); 
        cnn.Open(); 
        AdomdCommand cmd = new AdomdCommand(@" 
           <Discover xmlns='urn:schemas-microsoft-com:xml-analysis'> 
             <RequestType>DBSCHEMA_CATALOGS</RequestType> 
             <Restrictions /> 
             <Properties /> 
           </Discover>", cnn); 
        cmd.Execute(); 
        cnn.Close(); 
    } 
}

Скрипт 1

Рис. 1

Это происходит потому, что, как уже неоднократно отмечалось выше, AdomdCommand воспринимает только InnerXml элемента <Command> XMLA-запроса, т.е. она может выполнять только запросы метода Execute. Ну вот так устроена ADOMD.NET.

Для выполнения Discover-запросов в ADOMD.NET существет метод GetSchemaDataSet(), который выполняется непосредственно над соединением AdomdConnection. Первым параметром в нем является строка с названием риквест тайпа или его гуидом. Гуиды риквест тайпов можно видеть при помощи Скрипта 4 поста Метод Discover. Кроме того, добрые люди, писавшие ADOMD.NET, предусмотрели enum (перечислимый тип) AdomdSchemaGuid, который избавляет от необходимости обременять свою память или заниматься копи-пастом гуидов. Скажем, вместо строки "DBSCHEMA_CATALOGS" можно написать AdomdSchemaGuid.Catalogs и т.д. (см., к примеру, Рис.3).

AdomdConnection cnn = new AdomdConnection("Data Source=localhost"); 
cnn.Open(); 
DataSet ds = cnn.GetSchemaDataSet("DBSCHEMA_CATALOGS", null); //Вторым параметром идут Restrictions 
cnn.Close(); 
DataTable dt = ds.Tables[0]; 
Debug.WriteLine(""); 
foreach (DataColumn c in dt.Columns) { Debug.Write(c.ColumnName); Debug.Write("; "); } 
foreach (DataRow r in dt.Rows) 
{ 
       Debug.WriteLine(""); 
       for (int i = 0; i < r.Table.Columns.Count; i++) 
       { 
              Debug.Write(r[i]); Debug.Write("; "); 
       } 
} 
Debug.WriteLine("\n");

Скрипт 2

Рис. 2

Как говорилось в посте Метод Discover, результатом Discover-запроса является реляционное множество записей (rowset). Его колонками являются те элементы, которые можно видеть в XSD-описании элемента <row> в результатах запроса Скрипт 1 поста Метод Discover:

<xsd:complexType name="row"> 
        <xsd:sequence> 
          <xsd:element sql:field="CATALOG_NAME" name="CATALOG_NAME" type="xsd:string" minOccurs="0" /> 
          <xsd:element sql:field="DESCRIPTION" name="DESCRIPTION" type="xsd:string" minOccurs="0" /> 
          <xsd:element sql:field="ROLES" name="ROLES" type="xsd:string" minOccurs="0" /> 
          <xsd:element sql:field="DATE_MODIFIED" name="DATE_MODIFIED" type="xsd:dateTime" minOccurs="0" /> 
        </xsd:sequence> 
      </xsd:complexType>

Скрипт 3

Эти результаты можно видеть на Рис.1 поста Метод Discover повыше обведенного фрагмента. Это шапка. Значения Analysis Services берет из недр директории, где лежат данные. Что-нибудь типа %ProgramFiles%\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\Data, в зависимости от того, куда происходила установка.

Дополнительными элементами канонического Discover-запроса в XMLA выступают Restrictions и Properties. В аналогичной ситуации Execute-запроса для передачи элементов запроса Parameters и Properties у AdomdCommand существовали свойства-коллекции Parameters и Properties – см., напр., Скрипт 2 поста Параметризованные MDX-запросы. В случае Discover-запроса для передачи Restrictions предназначен второй параметр метода GetSchemaDataSet типа object[] или AdomdRestrictionCollection, а Properties, похоже, не передаются никак. То есть выполнить запрос Скрипта 5 из предыдущего поста нам еще удастся, например, вот так:

DataSet ds = cnn.GetSchemaDataSet(AdomdSchemaGuid.SchemaRowsets, new string[] { "MDSCHEMA_DIMENSIONS" });

Скрипт 4

или так:

AdomdRestrictionCollection restrictions = new AdomdRestrictionCollection(); 
restrictions.Add("SchemaName", "MDSCHEMA_DIMENSIONS"); 
DataSet ds = cnn.GetSchemaDataSet("DISCOVER_SCHEMA_ROWSETS", restrictions);

Скрипт 5

А вот, допустим, как ему подсунуть

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

из Скрипта 2 (тоже предыдущего поста), я уже не знаю. Ну нет нигде для GetSchemaDataSet коллекции Properties. Видимо, просматривая список Properties (Скрипт 3 поста Метод Discover), эти добрые люди решили, что в плане PropertiesXMLA избыточен, хватит одних Restrictions. Я не поленился заглянуть в профайлер и обнаружил, что когда идет запрос через GetSchemaDataSet, судя по всему, всегда подставляется стандартный набор свойств:

<PropertyList xmlns="urn:schemas-microsoft-com:xml-analysis"> 
  <LocaleIdentifier>1033</LocaleIdentifier> 
  <Content>SchemaData</Content> 
  <Format>Tabular</Format> 
</PropertyList>

где LocaleIdentifier определяется текущими установками, а база данных (Catalog), которая здесь явно не указана, по-видимому, берется из свойств соединения AdomdConnection.

... 
AdomdConnection cnn = new AdomdConnection("Data Source=localhost;Initial Catalog=Adventure Works DW 2008R2"); 
cnn.Open(); 
DataSet ds = cnn.GetSchemaDataSet(AdomdSchemaGuid.Dimensions, null); 
cnn.Close(); 
...

Скрипт 5

Рис. 3

Кроме того, как мы помним, всегда остается способ в обход ADOMD заслать Analysis Services напрямую XMLA в чистом виде, т.е. SOAP-запрос по типу Скрипта 1 поста Доступ по SOAP.

Переход на следующую серию.

Автор: Алексей Шуленин