mardi 2 mars 2021

Grille de données et LiteDB

Dans cet article, nous allons voir comment afficher une collection LiteDB dans un DataGridView. Pour cela, je vais créer une base LiteDB avec une collection. Puis je vais créer un formulaire de type DataGridView pour afficher les données de la collection. J'ajouterons à ce formulaire des fonctions d'ajout, modification et suppression de données.

LiteDB


LiteDB est une base de données "sans serveur" de type NoSQL se présentant sous la forme d'une simple Dll de moins de 500Ko. Elle ne nécessite ni installation, ni droit administrateur. LiteDB est donc facilement portable pour peu que le FrameWork soit installé sur le système.

Site de référence : http://www.litedb.org

Exemple


Dans cette exemple j'utilise LiteDB v3.1.4 (compatible v5.0.10). Pour fonctionner, il faut créer un dossier ldb au même niveau d'arborescence que le script, puis copier dans dossier lbd le fichier LiteDB.dll ainsi que son fichier xml.

 
####################################################################
#
#               Base de données : LiteBD v3.1.4 (compatible v5.0.10)
#                     Powershell.sekki.fr
#
# 1 - Créer un dossier ldb à côté du script.
# 2 - Télécharger et copier LiteDB.dll+xml dans le dossier ldb.
#
####################################################################

#Chemin courant.
$curpath = ""
if ($psISE) { $curpath = split-path -parent $psISE.CurrentFile.Fullpath }
else        { $curpath = Split-Path $MyInvocation.MyCommand.Path  }

#Charge les fonctions LiteDB.
Try   { [void][Reflection.Assembly]::LoadFile($curpath+"\ldb\LiteDB.dll") }
Catch { Write-Host "LiteDB.dll manquant.";Return 2 }

#Version LiteDB.
$global:VersionLDB = ([System.Diagnostics.FileVersionInfo]::GetVersionInfo(($curpath+"\ldb\LiteDB.dll")).FileVersion)[0]
Write-host "Vous utilisez LiteDB v$global:VersionLDB"

#Fonctions personnalisées : Converti le résultat de la query pour l'afficher.
function BsonToObj($bsn)
 {
   #Conversion (compatible LiteDB v3 et v5).
   $obj = New-Object System.Object
   $obj | Add-Member -type NoteProperty -name _id   -Value $bsn["_id"].AsObjectID
   $obj | Add-Member -type NoteProperty -name date  -Value $bsn["date"].AsString
   $obj | Add-Member -type NoteProperty -name info1 -Value $bsn["nom"].AsString
   $obj | Add-Member -type NoteProperty -name info2 -Value $bsn["prix"].AsInt32
   $obj | Add-Member -type NoteProperty -name info3 -Value $bsn["cat"].AsString
   $obj
 }

#Ouvrir/Créer une Base de Données.
$db = New-Object LiteDB.LiteDatabase(($curpath+"\ldb\LiteDB.db"),$null)

#Ouvrir/Créer une Collection.
$global:coll = $db.GetCollection("Info")

#Nouveau document Bson.
$bson = New-Object LiteDB.BsonDocument

#Fonction : Renvoi un nombre entre 0 et 100.
function GR() { Get-Random -minimum 0 -maximum 100 }

#Créer 5 enregistrements si la base est vide.
if (($global:coll.Count([LiteDB.Query]::all())) -eq 0)
  {
    for($i=0;$i -le 4;$i++)
     {
       $x = GR   #Nombre aléatoire entre 0 et 100.
       if ($x -le 50) { $nom = "Sekki";   $prix = $x; $cat = "Z" }
       else           { $nom = "Jumbor";  $prix = $x; $cat = "B" }

       #Ajouter un enregistrement dans la base de données.
       $bson["_id"]  = [LiteDB.ObjectId]::NewObjectId()
       $bson["date"] = date -format "dd/MM/yyyy"
       $bson["nom"]  = [string]$nom
       $bson["prix"] = [int]$prix
       $bson["cat"]  = [string]$cat
       write-host $nom $prix $cat
       [void]$global:coll.Insert($bson)   #Insère le document dans la collection.
     }
 }

#Fonction : Met à jour ou enregistre un objet dans la base (Écriture).
function SaveToBase($obj)
 {
   #Vérification.
   if ([string]::IsNullOrEmpty($obj._id)) { Return }
   
   #Vérifier si c'est un nouvel enregistrement ou une modification.
   if ($obj._id -eq "New") { $modifier = $false } else { $modifier = $true }

   #Création du Bson.
   if ($modifier)
     { #Modifier une ligne existante.
       $bsonid = New-Object LiteDB.ObjectId ([string]($obj._id))
       $bson   = $global:coll.FindOne([LiteDB.Query]::Eq("_id",$bsonid))
     }
   else
     { #Ajouter une nouvelle ligne.
       $bson = New-Object LiteDB.BsonDocument
       $bson["_id"] = [LiteDB.ObjectId]::NewObjectId()
     }
     
   #Tronc commun.   
   $bson["date"] = ([string]$obj.date)
   $bson["nom"]  = ([string]$obj.info1)
   $bson["prix"] = ([int]$obj.info2)
   $bson["cat"]  = ([string]$obj.info3)

   #Enregistrer.
   if ($modifier) { [void]$global:coll.Update($bson) }
   else           { [void]$global:coll.Insert($bson) }
 }

#Initialisation.
$global:delid = @()   #Tableau des lignes à supprimer.

#Formulaire.
$formA = New-Object Windows.Forms.Form
$formA.Text = "DataGridView-LiteDB."
$formA.BackColor = [System.Drawing.Color]::FromArgb(255,240,240,240)
    
#Taille de la fenêtre.
$formA.Size = New-Object Drawing.Point 400,300
$largeurA = $formA.width
$hauteurA = $formA.height
       
#DataGrid.
$DataGridA1 = New-Object System.Windows.Forms.DataGridView
$DataGridA1.Location = New-Object Drawing.Point 6,6
$DataGridA1.Size = New-Object Drawing.Point ($largeurA-28),($hauteurA-78)
$DataGridA1.ReadOnly = $false
$DataGridA1.AutoSize = $false
#$DataGridA1.EditMode = "EditOnEnter"
$DataGridA1.GridColor = "Black"
$DataGridA1.ScrollBars = "Vertical"
$DataGridA1.AllowUserToResizeRows = $true
$DataGridA1.BorderStyle = [System.Windows.Forms.BorderStyle]::None
$DataGridA1.BackgroundColor = [System.Drawing.Color]::FromArgb(255,240,240,240)
$DataGridA1.DefaultCellStyle.SelectionBackColor = [System.Drawing.Color]::FromArgb(255,70,149,218)
 
#Titre/Entête.
$DataGridA1.RowHeadersVisible    = $false
$DataGridA1.ColumnHeadersVisible = $true
$DataGridA1.ColumnHeadersHeightSizeMode = "DisableResizing"
$DataGridA1.EnableHeadersVisualStyles = $false
$DataGridA1.ColumnHeadersDefaultCellStyle.BackColor = [System.Drawing.Color]::FromArgb(255,70,149,218)
$DataGridA1.ColumnHeadersDefaultCellStyle.ForeColor = "White"
$DataGridA1.ColumnHeadersBorderStyle = "Single"
 
#Colonnes.
[void]$DataGridA1.Columns.Add((New-Object System.Windows.Forms.DataGridViewTextBoxColumn))
[void]$DataGridA1.Columns.Add((New-Object System.Windows.Forms.DataGridViewTextBoxColumn))
[void]$DataGridA1.Columns.Add((New-Object System.Windows.Forms.DataGridViewTextBoxColumn))
[void]$DataGridA1.Columns.Add((New-Object System.Windows.Forms.DataGridViewTextBoxColumn))
[void]$DataGridA1.Columns.Add((New-Object System.Windows.Forms.DataGridViewTextBoxColumn))
$DataGridA1.Columns[0].Name = "Id"
$DataGridA1.Columns[0].Visible = $false   #Masque la colonne Id.
$DataGridA1.Columns[1].Name = "Date"
$DataGridA1.Columns[2].Name = "Nom"
$DataGridA1.Columns[3].Name = "Prix"
$DataGridA1.Columns[4].Name = "Cat"
 
#Colonnes : Défini la tailles des colonnes.
foreach($column in $DataGridA1.Columns)
 {
   $column.SortMode     = "NotSortable"
   $column.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::Fill
 }
$DataGridA1.Columns[3].Width = 50   #Fixe la taille de la colonne.
$DataGridA1.Columns[4].Width = 50   #Fixe la taille de la colonne.
 
#Events.
$DataGridA1.Add_CellValueChanged({
  $r = $DataGridA1.SelectedCells[0].RowIndex
  $c = $DataGridA1.SelectedCells[0].ColumnIndex
  if ($DataGridA1.Rows[$r].Cells[0].Value -eq $null)
    {
      #Nouvelle ligne : Met la valeur "New" dans la colonne Id.
      #L'Id Bson sera généré plus tard lors de l'enregistrement.
      $DataGridA1.Rows[$DataGridA1.SelectedCells[0].RowIndex].Cells[0].Value="New"
    }
                                })

#Lier.
$formA.Controls.Add($DataGridA1)

#Bouton - Annuler.
$buttonA1 = New-Object Windows.Forms.Button
$buttonA1.Size = New-Object Drawing.Point 80,23
$buttonA1.Location = New-Object Drawing.Point ($largeurA-102),($hauteurA-67)
$buttonA1.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
$buttonA1.BackColor = [System.Drawing.Color]::FromArgb(255,225,225,225)
$buttonA1.Text = "Annuler"
$buttonA1.Add_Click({ $formA.Close() })   #Ferme la fenêtre sans enregistrer.
$formA.Controls.Add($buttonA1)
   
#Bouton - Supprimer.
$buttonA2 = New-Object Windows.Forms.Button
$buttonA2.Size = New-Object Drawing.Point 80,23
$buttonA2.Location = New-Object Drawing.Point ($largeurA-188),($hauteurA-67)
$buttonA2.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
$buttonA2.BackColor = [System.Drawing.Color]::FromArgb(255,225,225,225)
$buttonA2.Text = "Supprimer"
$buttonA2.Add_Click({
                      #Supprime les lignes sélectionnées.
                      foreach($data in $DataGridA1.SelectedCells)
                       {
                         $r = $data.RowIndex
                         if ($DataGridA1.Rows[$r])
                           {
                             $rowid  = $DataGridA1.Rows[$r].Cells[0].Value
                             #Ajoute l'Id au tableau des lignes à supprimer.
                             $global:delid += $rowid
                             #Supprime la ligne du DataGrid.
                             $DataGridA1.Rows.Remove($DataGridA1.Rows[$r])
                           }
                       }
                   })
$formA.Controls.Add($buttonA2)
 
#Bouton - OK.
$buttonA3 = New-Object Windows.Forms.Button
$buttonA3.Size = New-Object Drawing.Point 80,23
$buttonA3.Location = New-Object Drawing.Point ($largeurA-274),($hauteurA-67)
$buttonA3.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
$buttonA3.BackColor = [System.Drawing.Color]::FromArgb(255,225,225,225)
$buttonA3.Text = "OK"
$buttonA3.Add_Click({
                      #Supprimer les données.
                      foreach($rowid in $global:delid)
                       {
                        #Les nouvelles lignes ne sont pas traitées.
                         if ($rowid -ne "New")
                           {
                             #Convertir le String "Id" en Bson "ObjectId".
                             $bsonid = New-Object LiteDB.ObjectId $rowid
                             #Supprime la ligne de la table "Info".
                             switch ($global:VersionLDB)
                              {
                                "3" { $null = $global:coll.Delete([LiteDB.Query]::Eq("_id",$bsonid)) }
                                "5" { $null = $global:coll.DeleteMany([LiteDB.Query]::Eq("_id",$bsonid)) }
                                Default { Write-Host "Version LiteDB non prise en charge !" }
                              }
                           }
                       }

                      #Enregistrer les données.
                      foreach($data in $DataGridA1.Rows)
                       {
                         #Créer un nouvel objet avec les données de la ligne.
                         $savinfo = New-Object PSObject -Property @{ _id = ""; date  = ""; info1 = ""; info2 = 0; info3 = "" }
                         $savinfo._id   = $data.Cells[0].Value
                         $savinfo.date  = $data.Cells[1].Value
                         $savinfo.info1 = $data.Cells[2].Value
                         $savinfo.info2 = $data.Cells[3].Value
                         $savinfo.info3 = $data.Cells[4].Value
                         #Sauvegarder l'objet dans la collection "Info".
                         $null = SaveToBase $savinfo
                       }
                       
                      #Fermer la fenêtre.
                      $formA.Close()
                   })
$formA.Controls.Add($buttonA3)
     
#Event.
$formA.Add_Load({   $DataGridA1.ClearSelection() })
$formA.Add_Resize({
     #Ajuster la position des contrôles lorsque la fenêtre change de taille.
     $largeurA          = $formA.width; $hauteurA = $formA.height
     $DataGridA1.Size   = New-Object Drawing.Point ($largeurA-28),($hauteurA-78)
     $buttonA1.Location = New-Object Drawing.Point ($largeurA-102) ,($hauteurA-67)
     $buttonA2.Location = New-Object Drawing.Point ($largeurA-188),($hauteurA-67)
     $buttonA3.Location = New-Object Drawing.Point ($largeurA-274),($hauteurA-67)
                 })

#Chargement des données.
$base = $global:coll.Find([LiteDB.Query]::all())
foreach($bson in $base)  
 {
   #Ajoute la ligne dans le DataGridView.
   $line = BsonToObj $bson
   [void]$DataGridA1.Rows.Add($line._id, $line.date, $line.info1, $line.info2, $line.info3 )
 }
     
#Afficher.
[void]$formA.ShowDialog()

#Fermer la base de données.
$db.Dispose()

#Fin.