Renaud Harduin
ADOMD.Net : Accès aux bases multidimensionnelles (et présentation avec DataGridView)
L'objet de cet article est de présenter comment se fait l'accès aux données de cube via ADOMD.Net qui est aux bases multidimensionnelles ce qu'est ADO
Par Renaud Harduin publié le 17/04/2006 à 22:44, lu 7286 fois, 5 pages
 3 | II – Cellset et DataGridView
Téléchargez le code source - 111 Kb
II – Cellset et DataGridView
2.1 – ADOMD.Net et Cellset
Un CellSet peut être obtenu à partir d'une AdomdCommand. Toujours dans la façade, nous implémentons :
public CellSet getCellSet(string  mdxQuery)
{
  CellSet  cs;
  AdomdCommand  cmd = new AdomdCommand( mdxQuery, _mdConn);
   cs =  cmd.ExecuteCellSet();

  return  cs;
}

Lors de l'exécution de la requête, la commande nous renvoie un CellSet qui contient notamment :
  • Une matrice de donnée (propriété Cells et indexer du Cellset).
  • Des métadonnées concernant les axes colonne, ligne ... de cette matrice (Collection Axes)
  • Des métadonnées concernant la requête en elle-même OlapInfo
Dès lors où notre façade renvoie un CellSet, il faut penser à créer la référence vers Microsoft.AnalysisServices.AdomdClient dans notre projet coté UI.
La matrice (Cells et indexer) ne contient donc que les données. Elle a autant de colonnes qu'il existe de croisements (ou positions) sur l'axe colonne (Axes[0].Positions.Count) et autant de lignes qu'il existe de croisements (ou positions) sur l'axe ligne (Axes[1].Positions.Count).
Tout l'art va consister à itérer dans cette matrice avec un jeu de coordonnées et de mettre en face la bonne information dans des « header » :
2.2 – Restitution simple dans le DataGridView (DGV)
Nous allons « détourner » le Dgv pour afficher les données de manière un peu plus élégante :



L'idée est de « jouer » avec les cellules du Dgv comme dans une feuille Excel pour simuler des entêtes avec plusieurs colonnes graces aux cellules elles mêmes (on n'utilisera donc pas les Header du Dgv) et de charger les données en correspondance.

A cet effet, nous développer la méthode DisplayCellSetSimply

2.2.1 – Setup du DataGridView
private  void displayCellSetSimply(CellSet  cs)
{
  int i;
  int j;
 
  OlapInfo olapInfo =  cs.OlapInfo;
  OlapInfoAxis columnAxisInfo = olapInfo.AxesInfo.Axes[0];
  OlapInfoAxis rowAxisInfo = olapInfo.AxesInfo.Axes[1];

  Axis columnAxis =  cs.Axes[0];
  Axis rowAxis =  cs.Axes[1];

  int colOffset = rowAxisInfo.Hierarchies.Count;
  int rowOffset = columnAxisInfo.Hierarchies.Count;

  int numberOfColumns = rowAxisInfo.Hierarchies.Count +  cs.Axes[0].Positions.Count;
  int numberOfRows = columnAxisInfo.Hierarchies.Count +  cs.Axes[1].Positions.Count;
  
  // 1 - DGV Setup
  DgvCube.ColumnCount = numberOfColumns;
  DgvCube.RowCount = numberOfRows;
  DgvCube.ColumnHeadersVisible = false;
  DgvCube.RowHeadersVisible = false;

Commentaire :
A cette étape, nous dimensionnons notre jeu de cellule dans le Dgv en agissant sur les propriétés ColumnCount et RowCount. S'il sagissait d'afficher simplement la matrice de données, on affecterait à ColumnCount le nombre de posistions de l'axe colonne (cs.Axes[0].Positions.Count). Ce ci dit, nous devons en plus, insérer les colonnes nécessaires pour afficher les « vrais-faux » entêtes.
C'est pour cela que nous rajoutons un colOffset qui contient le nombre de hierarchies affichée en colonne (que nous retrouvons en consultant cette fois ci les métadonnées OlapInfo). Le taille en nombre de colonnes est donc colOffset + cs.Axes[0].Positions.Count.

Le raisonnement est exactement le même sur l'axe des lignes.

2.2.2 - Chargement des entêtes de colonnes
  // 2 - Fill "Column Headers"
  for (i = 0; i < columnAxis.Positions.Count; i++)
  {
      for (j = 0; j < columnAxisInfo.Hierarchies.Count; j++)
      {
          DgvCube[i+colOffset, j].Value = columnAxis.Positions[i].Members[j].Caption;
          
          DgvCube[i + colOffset, j].Style.BackColor = Color.SteelBlue;
          DgvCube[i + colOffset, j].Style.ForeColor = Color.White;
      }
  }

Commentaire :
Si ma requête croise un niveau A et un niveau B, pour chaque combinaison A et B, il existe un objet position et position.Members[0].Caption me renvoie la valeur du membre de A pour cette position, et position.Members[1].Caption me renvoie la valeur du membre B pour cette position.
Nous remplissons les cellules de Header en exploitant ces informations.
  1. Le for ( i ... itère dans les positions de l'axe colonne.
  2. Le for(j... sur le Members itère lui dans les hierarchies pour adresser les valeurs de membre (toute chose égales par ailleurs)
  3. Nous affectons alors à la bonne cellule (attention au colOffset) la valeur membre adéquat (avec du color coding).
Cet exemple est assez caractéristique de l'exploitation simultanée des informations contenues dans OlapInfo (métadonnées) et de celles des Axes (réalisation de ces métadonnées).


2.2.3 – Chargement des header de ligne et des données
// 3 - Fill "Row Header" and "Data Area" at the same time
  for (j = 0; j < rowAxis.Positions.Count; j++)
  {
      for (i = 0; i < rowAxisInfo.Hierarchies.Count; i++)
      {
          DgvCube[i, j + rowOffset].Value = rowAxis.Positions[j].Members[i].Caption;
          DgvCube[i, j + rowOffset].Style.BackColor = Color.SteelBlue;
          DgvCube[i, j + rowOffset].Style.ForeColor = Color.White;
      }

      for (i = 0; i < columnAxis.Positions.Count; i++)
      {
          DgvCube[i + colOffset, j + rowOffset].Value =  cs.Cells[i, j].FormattedValue;
      }
  }

  DgvCube.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
  }
#endregion

Commentaire :
On itère dans l'axe ligne (for j...). Ensuite pour chaque pas :
  1. Tout comme pour les entêtes de colonne, on examine les métadonnées de la requête en bouclant sur les hierarchies (for i) en affichant dans la bonne cellule la valeur du membre concerné (Caption) ; Attention à bien positionner le rowOffset cette fois ci.
  2. Deuxième temps : pour chaque position, on va chercher colonne par colonne (deuxième boucle for i) les données dans le jeu de cellule avec :
DgvCube[i + colOffset, j + rowOffset].Value =  cs.Cells[i, j].FormattedValue;

L'enchainement des méthodes se fait lors du clic sur le bouton “Simple Grid” :
private void button2_Click(object sender, EventArgs e)
{
    DgvCube.DataSource = null;
    CellSet  cs = _mdFacade.getCellSet(C_MDXQUERY);
    displayCellSetSimply( cs);
}
 
» Démarrer une discussion