Skip to content

7. Caso di studio con Firebird 2.1

7.1. Installazione degli strumenti

Gli strumenti da installare sono i seguenti:

  • SGBD: [http://www.firebirdsql.org/en/firebird-2-1-5/];
  • uno strumento di amministrazione: EMS SQL Manager per InterBase/Firebird Freeware [http://www.sqlmanager.net/fr/products/ibfb/manager/download].

Negli esempi che seguono, l'utente è sysdba con la password masterkey.

Avviamo Firebird e poi lo strumento [SQL Manager Lite for Firebird], con il quale gestiremo SGBD.

  • In [1], avviamo Firebird (SGBD) dal menu Start. In questo caso, SGBD non è stato installato come servizio di Windows;
  • in [2], il servizio viene avviato. È apparsa un'icona in basso a destra dello schermo. Facendo clic con il tasto destro su di essa, è possibile arrestare il SGBD.

Ora avviamo lo strumento [SQL Manager Lite for Firebird] con cui gestiremo il SGBD [3].

  • in [4], creiamo un nuovo database;
  • in [5], si accetta;
  • in [5], si effettua l'accesso come SYSDBA / masterkey;
  • in [6], si indica la posizione del file che verrà creato. Infatti, il database verrà creato in un unico file;
  • in [7], si conferma il comando SQL che verrà eseguito;
  • in [8], il database è stato creato. Ora deve essere salvato in [EMS Manager]. Le informazioni sono corrette. Si esegue [OK];
  • in [9], ci si connette;
  • in [10], [EMS Manager] visualizza il database, per ora vuoto.

Ora collegheremo un progetto VS 2012 a questo database.

7.2. Creazione del database a partire dalle entità

Iniziamo duplicando la cartella del progetto [RdvMedecins-SqlServer-01] in [RdvMedecins-Firebird-01] e [1]:

  • in [2]; in VS 2012, eliminiamo il progetto [RdvMedecins-SqlServer-01] dalla soluzione;
  • in [3], il progetto è stato rimosso;
  • in [4], ne aggiungiamo un altro. Questo è contenuto nella cartella [RdvMedecins-Firebird-01] che abbiamo creato in precedenza;
  • in [5], il progetto caricato si chiama [RdvMedecins-SqlServer-01];
  • in [6], ne cambiamo il nome in [RdvMedecins-Firebird-01]
  • in [7], si aggiunge un altro progetto alla soluzione. Questo è contenuto nella cartella [RdvMedecins-SqlServer-01] del progetto che abbiamo eliminato dalla soluzione in precedenza;
  • in [8], il progetto [RdvMedecins-SqlServer-01] è stato reinserito nella soluzione.

Il progetto [RdvMedecins-Firebird-01] è identico al progetto [RdvMedecins-SqlServer-01]. Dobbiamo apportare alcune modifiche. In [App.config], modificheremo la stringa di connessione e il progetto [DbProviderFactory], che dovrà essere adattato a ciascun progetto SGBD.


<!-- stringa di connessione al database -->
  <connectionStrings>
    <add name="monContexte" connectionString="User=SYSDBA;Password=masterkey;Database=D:\data\istia-1213\c#\dvp\Entity Framework\databases\firebird\RDVMEDECINS-EF.GDB;DataSource=localhost;
Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;" providerName="FirebirdSql.Data.FirebirdClient" />
  </connectionStrings>
  <!-- il provider factory -->
  <system.data>
    <DbProviderFactories>
      <add name="Firebird Client Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.7.7.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c" />
    </DbProviderFactories>
  </system.data>
  • riga 3: l’utente e la sua password, nonché il percorso completo del database Firebird;
  • righe 8-10: il DbProviderFactory. La riga 9 fa riferimento a un DLL [FirebirdSql.Data.FirebirdClient] che non abbiamo. Lo si ottiene con NuGet e [1]:
  • in [2], nella barra di ricerca si digita la parola chiave firebird;
  • in [3], si seleziona il pacchetto [Firebird ADO.NET Data Provider]. Si tratta di un connettore ADO.NET per Firebird;
  • in [4], il nuovo codice;
  • in [5], in [App.config], occorre inserire la versione corretta di DLL. La si trova nelle sue proprietà.

Nel file [Entites.cs], è necessario adattare lo schema delle tabelle che verranno generate:


  [Table("MEDECINS")]
  public class Medecin : Personne
  {...}

  [Table("CLIENTS")]
  public class Client : Personne
  {...}

  [Table("CRENEAUX")]
  public class Creneau
  {...}

  [Table("RVS")]
  public class Rv
  {...}

In questo caso, le tabelle non hanno uno schema.

Configuriamo l'esecuzione del progetto:

  • in [1], si assegna un altro nome all'assembly che verrà generato;
  • in [2], si assegna anche un altro spazio dei nomi predefinito;
  • in [3], si indica il programma da eseguire.

A questo punto non ci sono errori di compilazione. Eseguiamo il programma [CreateDB_01]. Si ottiene la seguente eccezione:

Exception non gérée : System.Data.MetadataException: Le schéma spécifié n'est pas valide. Erreurs :
(11,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(23,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(33,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(43,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
   à System.Data.Metadata.Edm.StoreItemCollection.Loader.ThrowOnNonWarningErrors
()
   ...
   à RdvMedecins_01.CreateDB_01.Main(String[] args) dans d:\data\istia-1213\c#\d
vp\Entity Framework\RdvMedecins\RdvMedecins-Oracle-01\CreateDB_01.cs:ligne 15

Ricordiamo di aver riscontrato lo stesso errore con MySQL, Oracle e PostgreSQL. È legato al tipo del campo Timestamp delle entità. Applichiamo la stessa modifica utilizzata per i due precedenti SGBD. Nelle entità, sostituiamo le tre righe


    [Column("TIMESTAMP")]
    [Timestamp]
    public byte[] Timestamp { get; set; }

con le seguenti:


    [ConcurrencyCheck]
    [Column("VERSIONING")]
    public int? Versioning { get; set; }

Modifichiamo quindi il tipo della colonna, che passa da byte[] a int?. Nel SGBD, utilizzeremo delle procedure memorizzate per incrementare questo intero di un'unità ogni volta che verrà inserita o modificata una riga.

Applichiamo la modifica precedente alle quattro entità, quindi rieseguiamo l’applicazione. A questo punto otteniamo il seguente errore:

1
2
3
4
5
Exception non gérée : FirebirdSql.Data.FirebirdClient.FbException: lock time-out on wait transaction object D:\DATA\ISTIA-1213\C#\DVP\ENTITY FRAMEWORK\DATABASES\FIREBIRD\RDVMEDECINS-EF.GDB è in uso ---> FirebirdSql.Data.Common.IscException: timeout di blocco sulla transazione in attesa
object D:\DATA\ISTIA-1213\C#\DVP\ENTITY FRAMEWORK\DATABASES\FIREBIRD\RDVMEDECINS
-EF.GDB is in use
...
   à RdvMedecins_01.CreateDB_01.Main(String[] args) dans d:\data\istia-1213\c#\dvp\Entity Framework\RdvMedecins\RdvMedecins-Firebird-01\CreateDB_01.cs:riga 15

La riga 1 indica che il database è in uso. Mi sembra che non fosse così e non sono riuscito a risolvere questo problema.

Non importa. Creeremo manualmente il database [RDVMEDECINS-EF] con lo strumento [EMS Manager for Firebird]. Non descriveremo tutti i passaggi, ma solo quelli più importanti.

Il database Firebird sarà il seguente:

Le tabelle

  • in [1], ID è una chiave primaria con l’attributo Autoincrement. Verrà generata automaticamente da SGBD;

Le diverse tabelle presentano le chiavi primarie e esterne che queste stesse tabelle avevano negli esempi precedenti. Le chiavi esterne hanno l’attributo ON, DELETE e CASCADE.

I generatori

Come nel caso di Oracle e PostgreSQL, abbiamo creato dei generatori di numeri consecutivi. Ce ne sono 5: [1].

  • [CLIENTS_ID_GEN] verrà utilizzato per generare la chiave primaria della tabella [CLIENTS];
  • [MEDECINS_ID_GEN] verrà utilizzato per generare la chiave primaria della tabella [MEDECINS];
  • [CRENEAUX_ID_GEN] verrà utilizzato per generare la chiave primaria della tabella [CRENEAUX];
  • [RVS_ID_GEN] verrà utilizzato per generare la chiave primaria della tabella [RVS];
  • [VERSIONS_GEN] verrà utilizzato per generare i valori delle colonne [VERSIONING] di tutte le tabelle.

I trigger

Un trigger è una procedura eseguita da SGBD prima o dopo un evento (Inserimento, Modifica, Cancellazione) in una tabella. Ne abbiamo 8 [1]:

Diamo un'occhiata al codice DDL del trigger [BI_CLIENTS_ID] che popola la colonna [ID] della tabella [CLIENTS]:

1
2
3
4
5
6
7
8
CREATE TRIGGER BI_CLIENTS_ID FOR CLIENTS
ACTIVE BEFORE INSERT
POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
      NEW.ID = GEN_ID(CLIENTS_ID_GEN, 1);
END^
  • riga 2: prima di ogni inserimento nella tabella [CLIENTS];
  • righe 6-7: se la colonna ID è NULL, allora le viene assegnato il valore successivo del generatore di numeri [CLIENTS_ID_GEN].

I trigger [ BI_CLIENTS_ID, BI_MEDECINS_ID, BI_CRENEAUX_ID, BI_RVS_ID] sono tutti costruiti allo stesso modo.

Esaminiamo ora il codice DDL del trigger [CLIENTS_VERSION_TRIGGER] che popola la colonna [VERSIONING] della tabella [CLIENTS]:

1
2
3
4
5
6
7
CREATE TRIGGER CLIENTS_VERSION_TRIGGER FOR CLIENTS
ACTIVE BEFORE INSERT OR UPDATE
POSITION 1
AS
BEGIN
  NEW."VERSIONING" = GEN_ID(VERSIONS_GEN,1);
END^
  • righe 1-3: prima di ogni operazione INSERT o UPDATE sulla tabella [CLIENTS];
  • riga 6: la colonna ["VERSIONING"] riceve il seguente valore dal generatore di numeri [VERSIONS_GEN]. Questo generatore alimenta le colonne ["VERSIONING"] delle quattro tabelle.

I trigger [MEDECINS_VERSION_TRIGGER, CRENEAUX_VERSION_TRIGGER, RVS_VERSION_TRIGGER] funzionano in modo analogo.

Lo script per la generazione delle tabelle del database Firebird [RDVMEDECINS-EF] è stato inserito nella cartella [RdvMedecins / databases / Firebird]. Il lettore potrà caricarlo ed eseguirlo per creare le proprie tabelle.

Fatto ciò, è possibile eseguire i vari programmi del progetto. Essi forniscono gli stessi risultati ottenuti con SQL Server, ad eccezione del programma [ModifyDetachedEntities], che va in crash per lo stesso motivo per cui si era bloccato con Oracle e MySQL. Il problema si risolve allo stesso modo. È sufficiente copiare il programma [ModifyDetachedEntities] dal progetto [RdvMedecins-Oracle-01] nel progetto [RdvMedecins-Firebird-01].

7.3. Architettura multistrato basata su EF 5

Torniamo al nostro caso di studio descritto al paragrafo 2.

Inizieremo creando il livello di accesso ai dati [DAO]. A tal fine, duplichiamo il progetto console VS 2012 [RdvMedecins-SqlServer-02] in [RdvMedecins-Firebird-02] [1]:

  • in [2], eliminiamo il progetto [RdvMedecins-SqlServer-02];
  • in [3], si aggiunge un progetto esistente alla soluzione. Lo si prende dalla cartella [RdvMedecins-Firebird-02] appena creata;
  • in [4], il nuovo progetto porta il nome di quello che è stato eliminato. Ne cambieremo il nome;
  • in [5], abbiamo modificato il nome del progetto;
  • in [6], si modificano alcune delle sue proprietà, come in questo caso il nome dell’assembly;
  • in [7], la cartella [Models] viene eliminata per essere sostituita dalla cartella [Models] del progetto [RdvMedecins-Firebird-01]. Infatti, i due progetti condividono gli stessi modelli.
  • in [8], i riferimenti attuali del progetto;
  • in [9], è stato aggiunto il connettore ADO.NET di Firebird tramite lo strumento NuGet.

Nel file [App.config], si sostituiscono le informazioni del database SQL Server con quelle del database Firebird. Queste si trovano nel file [App.config] del progetto [RdvMedecins-Firebird-01]:


<!-- stringa di connessione al database -->
  <connectionStrings>
    <add name="monContexte" connectionString="User=SYSDBA;Password=masterkey;Database=D:\data\istia-1213\c#\dvp\Entity Framework\databases\firebird\RDVMEDECINS-EF.GDB;DataSource=localhost;
Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;" providerName="FirebirdSql.Data.FirebirdClient" />
  </connectionStrings>
  <!-- il provider factory -->
  <system.data>
    <DbProviderFactories>
      <add name="Firebird Client Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.7.7.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c" />
    </DbProviderFactories>
  </system.data>

Anche gli oggetti gestiti da Spring cambiano. Attualmente abbiamo:


  <!-- configurazione Spring -->
  <spring>
    <context>
      <resource uri="config://spring/objects" />
    </context>
    <objects xmlns="http://www.springframework.net">
      <object id="rdvmedecinsDao" type="RdvMedecins.Dao.Dao,RdvMedecins-SqlServer-02" />
    </objects>
</spring>

La riga 7 fa riferimento all'assembly del progetto [RdvMedecins-SqlServer-02]. L'assembly è ora [RdvMedecins-Firebird-02].

Fatto ciò, siamo pronti per eseguire il test del livello [DAO]. Prima è necessario assicurarsi di popolare il database (programma [Fill] del progetto [RdvMedecins-Firebird-01]). Il programma di test viene eseguito con successo.

Creiamo il DLL del progetto come è stato fatto per il progetto [RdvMedecins-SqlServer-02] e raggruppiamo l’tutti i file DLL del progetto in una cartella [lib] creata all’interno di [RdvMedecins-Firebird-02]. Questi saranno i riferimenti del progetto web [RdvMedecins-Firebird-03] che seguirà.

  

Ora siamo pronti per costruire il livello [ASP.NET] della nostra applicazione:

Partiremo dal progetto [RdvMedecins-SqlServer-03]. Duplichiamo la cartella di questo progetto in [RdvMedecins-Firebird-03] e [1]:

  • in [2]; con VS 2012 Express per il Web, apriamo la soluzione della cartella [RdvMedecins-Firebird-03];
  • in [3], modifichiamo sia il nome della soluzione che quello del progetto;
  • in [4], i riferimenti attuali del progetto;
  • in [5], li eliminiamo;
  • in [6], per sostituirli con riferimenti a DLL che abbiamo appena salvato in una cartella [lib] del progetto [RdvMedecins-Firebird-02].

Non ci resta che modificare il file [Web.config]. Sostituiamo il suo contenuto attuale con quello del file [App.config] del progetto [RdvMedecins-Firebird-02]. Fatto ciò, eseguiamo il progetto web. Funziona. Non dimentichiamo di popolare il database prima di eseguire l’applicazione web.