Skip to content

7. Caso di studio con Firebird 2.1

7.1. Installazione degli strumenti

Gli strumenti da installare sono i seguenti:

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

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

Avviamo Firebird e poi lo strumento [SQL Manager Lite for Firebird], che useremo per amministrare il DBMS.

  • In [1], avviamo il DBMS Firebird dal menu Start. In questo caso, il DBMS non è stato installato come servizio di Windows;
  • in [2], il servizio viene avviato. Un'icona appare nell'angolo in basso a destra dello schermo. Facendo clic con il tasto destro del mouse su di essa è possibile arrestare il DBMS.

Ora avviamo lo strumento [SQL Manager Lite for Firebird], che useremo per amministrare il DBMS [3].

  • In [4], creiamo un nuovo database;
  • In [5], confermiamo;
  • In [5], effettuiamo l'accesso come SYSDBA / masterkey;
  • In [6], specifichiamo la posizione del file da creare. Il database verrà creato come un unico file;
  • In [7], convalidiamo l'istruzione SQL da eseguire;
  • In [8], il database è stato creato. Ora deve essere registrato in [EMS Manager]. Le informazioni sono corrette. Fare clic su [OK];
  • In [9], effettua l'accesso;
  • In [10], [EMS Manager] visualizza il database, che al momento è vuoto.

Ora collegheremo un progetto VS 2012 a questo database.

7.2. Creazione del database dalle entità

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

  • in [2], in VS 2012, rimuoviamo il progetto [RdvMedecins-SqlServer-01] dalla soluzione;
  • in [3], il progetto è stato rimosso;
  • in [4], ne aggiungiamo un altro. Questo proviene dalla cartella [RdvMedecins-Firebird-01] che abbiamo creato in precedenza;
  • In [5], il progetto caricato si chiama [RdvMedecins-SqlServer-01];
  • In [6], ne modifichiamo il nome in [RdvMedecins-Firebird-01]
  • in [7], aggiungiamo un altro progetto alla soluzione. Questo progetto proviene dalla cartella [RdvMedecins-SqlServer-01] del progetto che abbiamo precedentemente rimosso dalla soluzione;
  • in [8], il progetto [RdvMedecins-SqlServer-01] è stato aggiunto nuovamente alla 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 [DbProviderFactory], che devono essere adattati per ogni DBMS.


<!-- connection chain on base -->
  <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>
  <!-- the factory provider -->
  <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: nome utente e password, oltre al percorso completo del database Firebird;
  • Righe 8–10: il DbProviderFactory. La riga 9 fa riferimento a una DLL [FirebirdSql.Data.FirebirdClient] che non abbiamo. Possiamo ottenerla utilizzando NuGet [1]:
  • in [2], digitare la parola chiave "firebird" nella casella di ricerca;
  • in [3], selezionare il pacchetto [Firebird ADO.NET Data Provider]. Si tratta di un connettore ADO.NET per Firebird;
  • in [4], il nuovo riferimento;
  • in [5], in [App.config], è necessario specificare la versione corretta della DLL. È possibile trovarla nelle sue proprietà.

Nel file [Entities.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
  {...}

Qui, le tabelle non hanno uno schema.

Configuriamo l'esecuzione del progetto:

  • in [1], assegniamo un nome diverso all'assembly che verrà generato;
  • in [2], specifichiamo anche uno spazio dei nomi predefinito diverso;
  • in [3], specifichiamo il programma da eseguire.

A questo punto, non ci sono errori di compilazione. Eseguiamo il programma [CreateDB_01]. Otteniamo 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. Ciò è legato al tipo del campo Timestamp nelle entità. Apportiamo la stessa modifica effettuata con i due DBMS precedenti. Nelle entità, sostituiamo le tre righe


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

con quanto segue:


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

Modifichiamo quindi il tipo della colonna da byte[] a int?. Nel DBMS, useremo procedure memorizzate per incrementare questo numero intero di uno ogni volta che viene inserita o modificata una riga.

Applichiamo la modifica sopra descritta a tutte e quattro le entità e quindi rieseguiamo l'applicazione. A questo punto riceviamo 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 is in use ---> FirebirdSql.Data.Common.IscException: lock time-out on wait transaction
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:ligne 15

La riga 1 indica che il database è in uso. Non credo che fosse così, e non sono riuscito a risolvere il problema.

Non importa. Creeremo il database [RDVMEDECINS-EF] manualmente utilizzando lo strumento [EMS Manager for Firebird]. Non descriveremo ogni singolo passaggio, ma solo quelli più importanti.

Il database Firebird sarà il seguente:

Le tabelle

  • In [1], ID è una chiave primaria con l'attributo </span>*Autoincrement*. Verrà generata automaticamente dal DBMS;

Le varie tabelle hanno le stesse chiavi primarie e esterne degli esempi precedenti. Le chiavi esterne hanno l'attributo ON DELETE CASCADE.

I generatori

Come per Oracle e PostgreSQL, abbiamo creato dei generatori di numeri sequenziali. 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] in tutte le tabelle.

Trigger

Un trigger è una procedura eseguita dal DBMS prima o dopo un evento (Insert, Update, Delete) 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, assegnarle il valore successivo dal 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 per il 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 valore successivo dal generatore di numeri [VERSIONS_GEN]. Questo generatore popola le colonne ["VERSIONING"] delle quattro tabelle.

I trigger [MEDECINS_VERSION_TRIGGER, CRENEAUX_VERSION_TRIGGER, RVS_VERSION_TRIGGER] sono simili.

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

Una volta fatto ciò, è possibile eseguire i vari programmi del progetto. Essi producono gli stessi risultati ottenuti con SQL Server, ad eccezione del programma [ModifyDetachedEntities], che va in crash per lo stesso motivo per cui si bloccava 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 nel paragrafo 2.

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

  • in [2], eliminiamo il progetto [RdvMedecins-SqlServer-02];
  • in [3], aggiungiamo un progetto esistente alla soluzione. Lo prendiamo dalla cartella [RdvMedecins-Firebird-02] appena creata;
  • in [4], il nuovo progetto ha lo stesso nome di quello che è stato eliminato. Ne cambieremo il nome;
  • In [5], abbiamo modificato il nome del progetto;
  • In [6], modifichiamo alcune delle sue proprietà, come il nome dell'assieme;
  • in [7], la cartella [Models] viene eliminata e sostituita dalla cartella [Models] del progetto [RdvMedecins-Firebird-01]. Questo perché entrambi i progetti condividono gli stessi modelli.
  • in [8], i riferimenti attuali del progetto;
  • In [9], il connettore Firebird ADO.NET è stato aggiunto utilizzando lo strumento NuGet.

Nel file [App.config], sostituire le informazioni relative al database SQL Server con quelle del database Firebird. Queste informazioni sono disponibili nel file [App.config] del progetto [RdvMedecins-Firebird-01]:


<!-- connection chain on base -->
  <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>
  <!-- the factory provider -->
  <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:


  <!-- spring configuration -->
  <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]. Innanzitutto, dobbiamo assicurarci che il database sia popolato (utilizzando il programma [Fill] del progetto [RdvMedecins-Firebird-01]). Il programma di test viene superato.

Creiamo la DLL del progetto come abbiamo fatto per il progetto [RdvMedecins-SqlServer-02] e raccogliamo tutte le DLL del progetto in una cartella [lib] creata in [RdvMedecins-Firebird-02]. Questi saranno i riferimenti per il progetto web [RdvMedecins-Firebird-03] che seguirà.

  

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

Inizieremo con il progetto [RdvMedecins-SqlServer-03]. Duplicheremo questa cartella di progetto in [RdvMedecins-Firebird-03] [1]:

  • in [2], utilizzando VS 2012 Express for the Web, apriamo la soluzione nella 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 i riferimenti alle DLL che abbiamo appena salvato in una cartella [lib] all'interno del progetto [RdvMedecins-Firebird-02].

Non resta che modificare il file [Web.config]. Sostituiamo il suo contenuto attuale con il contenuto del file [App.config] del progetto [RdvMedecins-Firebird-02]. Una volta fatto questo, eseguiamo il progetto web. Funziona. Non dimenticate di popolare il database prima di eseguire l'applicazione web.