Введение в 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), эти добрые люди решили, что в плане Properties XMLA избыточен, хватит одних 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.
Алексей Шуленин