Le décisionnel est un de mes domaines fonctionnels d'origine, il m'arrive de temps à autre de répondre à des questions clients sur cette problématique.
Un client m'a donc récemment posé une colle. Comment faire pour qu'une application puisse créer puis attaquer un cube local programmatiquement via MDX sans passer par la case serveur d'analyse (Analysis Services en l'occurence) ?
Pour ce faire, je me suis tourné du côté de XML for Analysis (XMLA) afin de définir le schéma de mon cube. XMLA est une norme respectée par MS Analysis Services, Hyperion, SAP et SAS (autrement dit c'est un standard de fait sur le marché). Pour celles et ceux intéressés par la norme voyez du côté de ce lien.XMLA sert essentiellement de protocole de dialogue entre un serveur d'analyse et des applications tierces en s'appuyant sur SOAP. Une chose intéressante avec XMLA est qu'en plus d'être un protocole permettant l'interrogation de cubes analytiques, il permet aussi la création de ceux-ci.
Le schéma XMLA sera donc interprété via ADOMD.Net dans sa partie cliente (téléchargeable sur le site Microsoft). Une fois le cube local (*.cub) généré par ADOMD.Net je l'attaque classiquement.
Pour le bien de la démonstration, j'utilise la base Adventure Works afin d'aller chercher mes données mais toute source de données disposant d'une chaîne de connexion fera l'affaire.
1er problème : comment créer mon script XMLA ?
- 1ère solution : je me tape la grammaire XMLA et je crée tout à la main. Cette solution est sympathique mais prend énormément de temps.
- 2ème solution : j'utilise mon serveur d'analyse propiétaire et j'extraie un script XML. Loin de moi la fainéantise, mais j'ai privilégié cette approche.
Je vous conseille de récupérer une version gratuite SQL Server Express Advanced disposant des fonctionnalités d'analyse ainsi que les outils Visual Studio For Business Intelligence.
Je crée donc d'abord un projet d'analyse sous Visual Studio avec une source de données ici sur ma base relationnelle Adventure Works.

Ma DataSourceView est assez simple :
J'ai donc une table de fait Customer qui va disposer d'une seule mesure (Le nombre de client) exposée selon 2 dimensions : les territoires de vente et les magasins. Un schéma très simple pour l'exercice.
Une fois publié, je sélectionne ma base de données sous management studio (à télécharger) après m'y être connecté et j'exporte le script XMLA. Bien faire attention d'exporter la base et non le cube !

J'obtiens un script que je sauvegarde sous mon répertoire c:\textcube.txt.
2ème problème : comment créer la requête qui va manipuler le script pour générer le cube local ?
Le script de création seul ne suffit pas. Il faut l'englober dans un stub qui va se connecter à la source de données. Voici ce script gratuitement :) :
<Batch xmlns='http://schemas.microsoft.com/analysisservices/2003/engine'>
CUBESCRIPT
<Parallel>
<Process xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
<Object>
<DatabaseID>Analysis Services Project1</DatabaseID>
</Object>
<Type>ProcessFull</Type>
<WriteBackTableCreation>UseExisting</WriteBackTableCreation>
</Process>
</Parallel>
</Batch>
A la place de CUBESCRIPT, je vais remplacer programmatiquement le schéma créé précédemment.Le stub est sauvegardé dans un autre fichier texte xmlastub.txt.
Notez bien que le DatabaseID doit être identique à celui présent dans le fichier textcube.txt.
S'en suit un programme C# qui va construire la requête :
AdomdConnection conn = new AdomdConnection();
conn.ConnectionString = string.Format("Provider=MSOLAP;Data Source={0}", "c:\\cubedemo.cub");
try {
conn.Open();
AdomdCommand cmd = new AdomdCommand();
cmd.Connection = conn;
string xmlastub = File.OpenText("C:\\xmlastub.txt").ReadToEnd();
string xmlacube = File.OpenText("C:\\TestCube.txt").ReadToEnd();
cmd.CommandText = xmlastub.Replace("CUBESCRIPT", xmlacube);
cmd.Execute();
Console.WriteLine("ok"); }
catch (Exception ex) { Console.WriteLine(ex.Message); }
finally { conn.Dispose(); } Console.ReadLine();
Le cube est maintenant généré, il n'y a plus qu'à l'attaquer.
Une petite requête MDX pour la route :
AdomdConnection conn = new AdomdConnection();
conn.ConnectionString = string.Format("Provider=MSOLAP;Data Source={0}", "c:\\cubedemo.cub");
try
{
conn.Open();
AdomdCommand cmd = new AdomdCommand();
cmd.Connection = conn;
cmd.CommandText = "select {[Measures].[Customer Count]} on columns, {[Store].[Business Entity ID].[Business Entity ID].Members} on rows from [MonTest]";
AdomdDataReader monReader = cmd.ExecuteReader();
while (monReader.Read())
{
//lecture
}
Console.WriteLine("ok");
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
finally { conn.Dispose(); } Console.ReadLine();
Voilà !
Alexandre Equoy
PS : Si vous souhaitez changer la chaîne de connexion de la source, vous trouverez dans le fichier XMLA les lignes suivantes :
<DataSources>
<DataSource xsi:type="RelationalDataSource">
<ID>AdventureWorks</ID>
<Name>AdventureWorks</Name>
<ConnectionString>Provider=SQLNCLI10.1;Data Source=WVFROLDU01\SQL2008_ENT;Integrated Security=SSPI;Initial Catalog=AdventureWorks</ConnectionString>
<ImpersonationInfo>
<ImpersonationMode>ImpersonateServiceAccount</ImpersonationMode>
</ImpersonationInfo>
<Timeout>PT0S</Timeout>
</DataSource>
</DataSources>
Sachez aussi qu'Excel est capable d'ouvrir un fichier *.cub directement ce qui permet d'accéder aux fonctionnalités décisonnelles dans Excel sur ce cube local.
TestCube.rar (34,13 kb)