Samstag, 17. Juli 2010

Erste Schritte mit ADOMD.NET

In den letzten Jahren habe ich eine ganze Reihe von Vorträgen über den Zugriff auf Analysis Services Cubes mittels .net Code und ADOMD.NET gehalten. Da die Funktionsweise eigentlich äußert einfach ist, habe ich aber bisher wenig bis wohl gar nichts dazu geschrieben. Das möchte ich nun nachholen, da sich hier bei mir die Nachfragen langsam häufen! :-)

Also, was ist ADOMD.NET eigentlich, was kann das und kostet das was?

ADOMD.NET ist ein sogenannter Data Provider von Microsoft für das .net Framework und bietet u. a. aus meiner .net Anwendung heraus die Möglichkeit auf SQL Server Analysis Services Cubes zuzugreifen. Wichtig ist dabei zu verstehen, dass ADOMD.NET kein fertiges BI Tool oder Control ist, welches ich nur noch einbinden muss und damit eine Art Excel-BI-Grid-GUI in meiner Anwendung habe. ADOMD.NET bietet mir im Code alle Möglichkeiten für den Zugriff auf die Daten, aber ich muss diese selbst kreativ nutzen . Wäre es dann nicht einfacher sich nicht gleich was Fertiges zu kaufen? Ok, wer schon mal eine Session von mir zum Thema gesehen hat, der kennt meine Antwort darauf. In der Regel wollen wir ja nicht den x’ten BI Client schreiben (auch wenn das wirklich Spaß machen kann!) oder unsere Anwendung um das Look & Feel von Excel erweitern, sondern unsere Anwender auf intelligente Art und Weise von den Fähigkeiten eines wahrscheinlich eh schon existierenden Cubes profitieren lassen. Mit Fähigkeiten meine u. a. ich die Flexibilität und Performance in Bezug auf sogenannte Ad-Hoc Queries und die damit verbundenen fast schon magischen Berechnungsmöglichkeiten. Das mit SQL Queries auf einer relationalen Datenbank abzubilden ist zwar meist möglich, aber dazu ist schon einiges an Experten KnowHow erforderlich und an die Performance eines Cubes ist meist gar nicht zu denken. Es lässt sich halt nicht jede Ad-Hoc Query vorher mit einem entsprechenden Index vorbereiten. Liegt nun mal in der Natur der Sache mit diesen Ad-Hoc Abfragen! Kommen wir kurz zu den Kosten. Good news, ADOMD.NET gibst von Microsoft zum SQL Server einfach dazu und ist Bestandteil des Feature Packs. Für den Zugriff wird nur eine gültige Lizenz für den Client benötigt. Also, wenn es aus lizenztechnischer Sicht möglich ist Excel als Client zu nutzen für die SSAS, dann auch ADOMD.NET. Details zu Lizenzen gibst bei Eurem freundlichen Microsoft Kontakt! Ach ja, Feature Packs! Hier kurz die Links, falls Ihr die nicht zur Hand habt:

Microsoft SQL Server 2008 R2 Feature Pack, Microsoft SQL Server 2008 Feature Pack & Microsoft SQL Server 2005 Feature Pack

Wie Ihr seht, gibst das Feature Pack für jede aktuellere Version des SQL Servers. Alles was ich Euch hier über ADOMD.NET schreibe, sollte auch mit jeder dieser Versionen möglich sein. Falls jemand andere Erfahrungen macht, dann Feedback an mich bitte.

Ok, auf was für Daten können wir nun in so einem Cube zugreifen? Ohne jetzt einen Grundlagenartikel über SSAS Cubes zu schreiben, hier mal kurz das Wichtigste kurz zusammengefasst:

Ein Cube besteht aus Dimensionen und Measures. Dabei könnt Ihr Euch die Dimensionen aus Geschäftsobjekte vorstellen und die Measures als die damit verbundenen Geschäftsprozesse bzw. die Ergebnisse der Geschäftsprozesse. Ein einfaches Beispiel ist der Verkauf von Artikel, dabei sind die Geschäftsobjekte “Artikel” und “Kunden” vorhanden und der Prozesse “Verkauf” und die damit verbundenen Umsätze. Nun kann in einem Cube entweder die Summe aller getätigten Verkäufe betrachtet werden oder diese werden auf Basis der Geschäftsobjekte gefiltert. Menschen mit einem Business Intelligence Hintergrund sprechen auch gern von dem “Schneiden” von Daten. Also zeige mir zum Beispiel nur die Verkäufe für die Artikelgruppen A, B & Z und nur für gewerbliche Kunden in Süddeutschland. Klingt doch einfach? Ist es auch, wobei irgendwann wird die Arbeit mit Cubes ein wenig tricky, aber für den Moment reicht uns das an Hintergrund. Das Schöne an Cubes ist es, dass sie solche und ähnliche Abfragen quasi in Gedankengeschwindigkeit verarbeiten und beantworten.

Eine Datenbank in Analysis Services ist in der Lage sich mittels einer ganzen Reihe von sogenannten Metadaten ausführlich selbst zu beschreiben. Wir haben u.a. folgende Metadaten im Zugriff:

  • Cubes
  • Dimensionen
  • Hierarchien
  • Level
  • Measures
  • KPIs
  • Named Sets

Macht es eigentlich Sinn, dass unsere Clients sich immer wieder alle Metadaten ziehen müssen? Auch dazu habe ich mich ja schon öfters geäußert. Aus der Erfahrung heraus ist dafür der Einsatz einer BI Middleware sinnvoll, welche u. a. ein Repository bereitstellt, welches alle Entitäten aller in der BI Umgebung verfügbaren Objekte bereitstellt. Dazu gehören neben der Datenbewirtschaftung (SSIS Pakete) und Reports (RDL Dateien) auch Informationen über unsere Cubes.

Häufig höre ich bei Vorträgen oder auch bei Coachings, dass es doch sicherlich viel zu aufwändig sei so einen Cube mit einzubinden. Da ist es doch einfacher zu versuchen mit den bisherigen Techniken voran zu kommen. Nun ja, was der Bauer nicht kennt, dass frisst er nicht.

Und bevor wir zu sehr in die Details einsteigen, hier ein erstes Codebeispiel für das Herstellen einer Verbindung mit einem Cube:

using Microsoft.AnalysisServices.AdomdClient;

AdomdConnection mdcon = new AdomdConnection(<constring>);
mdcon.open();

Wir machen was hoffentlich Sinnvolles…

mdcon.close();

Ok, das sieht doch schon mal ganz schlank aus. Kommen wir kurz zum Connectionstring.

Eine ganz einfache Variante ist die folgende: “datasource=localhost;catalog=adventure works dw 2008”. Ideal für Demo- und Testzwecke. Dummerweise reicht das nicht im echten Leben und es gibt fast schon unverschämt viele Parameter mit denen die Verbindung konfiguriert werden kann. Für den Moment soll das aber reichen. Unser Connectionstring zeigt auf den Server “localhost” und die Datenbank “Adventure Works DW 2008”. Und immer daran denken, eine Datenbank in SSAS kann mehrere Cubes umfassen!

So, ein weiterer Punkt ist der Namespace “Microsoft.AnalysisServices.AdomdClient” den wir hier verwenden. Damit wir ADOMD.NET überhaupt nutzen können, müssen wir zuerst im Visual Studio einen Verweis auf die “C:\Program Files\Microsoft.NET\ADOMD.NET\100\Microsoft.AnalysisServices.AdomdClient.dll” anlegen! Ab dann klappt das auch mit dem Namespace.

Und was können wir nun mit so einem AdomdConnection Objekt anfangen? Eine ganze Menge! Zunächst fragen wir einfach mal die Umgebung ab, damit wir wissen was uns da eigentlich so geboten wird. Also hier ein wenig mehr Code:

foreach (CubeDef cube in mdcon.Cubes)
  {
                if (cube.Name.StartsWith("$"))
                    continue;
                lbT1.Items.Add(cube.Name+ " ("+cube.LastProcessed.ToString()+")");               

                foreach (Dimension dim in cube.Dimensions)
                {
                    lbT1.Items.Add(" -> "+dim.Name);
                    
                    foreach (Hierarchy hier in dim.Hierarchies)
                    {
                        lbT1.Items.Add("   -> " + hier.Name);

                    } 
                } 
    }

Ist eigentlich recht einfach. Wir nehmen “mdcon”, also die Connection, und lassen uns in der Auflistung “Cubes” alle, nun ja, Cubes zeigen. Wir bekommen ein Cube Objekt, welches wiederum Eigenschaften hat, wie zum Beispiel “Name” & “LastProcessed”. In dem kleinen Codebeispiel schreibe ich die Werte in eine Listbox “lbT1”, daher dieses “lbT1.Items.Add” usw. Nun ja, und genauso machen wir weiter. Jeder Cube hat eine Auflistung für die verwendeten Dimensionen und die wiederum für die Hierarchien usw. Das ist doch einfach, oder?

Was können wir nun mit diesen Daten, welche die Cubes beschreiben, anfangen? Bereits eine ganze Menge! Hängt auch ein wenig von unserer Rolle im Unternehmen oder dem Projekt ab.

Wir können die Metadaten als Basis für spätere Abfragen nehmen. Gute Idee! Merken wir uns mal.

Wir können aber auch die Daten verwenden für den Aufbau einer Dokumentation. Wir lesen die Metadaten aus und schreiben sie relational weg. Vielleicht speichern wir auch die Daten gleich historisch ab, damit uns Änderungen auffallen bzw. wir diese dokumentiert haben. Darauf lassen sich super Reports bauen. Wozu? Kommt auf die Rolle von uns an. Wir können unsere eigene Arbeit dokumentieren und Veränderungen festhalten, also quasi unseren Arbeitsfortschritt. Aber genauso gut können wir die Arbeit anderer damit kontrollieren bzw. protokollieren wie sich über die Zeit hinweg ein Cube verändert. Das geht dann so in Richtung Projekt – und Qualitätsmanagement.

Kommen wir nun zu der eigentlichen Abfrage von Daten.

Einen Pferdefuss hat die Arbeit mit ADOMD.NET, denn Ihr müsst MDX für die Queries nutzen. Sofern Ihr bisher MDX aus dem Weg gegangen seit oder es einfach keinen Grund gab für Euch sich damit zu beschäftigen, nun ja, jetzt ist der Moment gekommen in dem MDX in Euer Leben tritt!

AdomdConnection mdcon = new AdomdConnection(tbConString.Text);

mdcon.Open();
AdomdCommand cmd = mdcon.CreateCommand();
cmd.CommandText = strMDXQuery;
CellSet cs = cmd.ExecuteCellSet();

Wir machen was Nützliches mit dem CellSet…

mdcon.Close();

Und schon haben wir unser Resultset als CellSet im Objekt “cs” vorliegen. Hier kommen so die wohl wichtigsten Zeilen mit denen Ihr ein CellSet zerlegen könnt. Mit den beiden folgenden Zeilen bekommt Ihr die Große des Resultsets zurück.

int x = cs.Axes[0].Positions.Count; // Anzahl Spalten

int y = cs.Axes[1].Positions.Count; // Anzahl Zeilen

So, nun wollen wir die Spalten- und Zeilenbeschriftungen auslesen. Für die Darstellung hat das CellSet die Eigenschaft “Caption” dabei und für Abfragen haben wir den UniqueName.

cs.Axes[0].Positions[xi].Members[0].Caption;

cs.Axes[0].Positions[xi].Members[0].UniqueName;

Ach ja, der eigentliche Wert ist ja auch noch da. Also nichts wie ran.

Value = cs[xi,yi].Value.ToString();

Das Ganze hier und noch viel, viel mehr schauen wir uns übrigens während des zweiten PASS Camp 2010 gemeinsam im Detail an.