progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

109
Università degli Studi di Trieste Facoltà di Ingegneria Corso di laurea specialistica in Ingegneria Informatica Progetto e Sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici Relatore : Laureando : Chiar.mo Prof. Maurizio Fermeglia Marko Paliska Anno accademico : 2013-2014

Upload: marko-paliska

Post on 08-Aug-2015

71 views

Category:

Engineering


2 download

TRANSCRIPT

Page 1: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

Università degli Studi di Trieste

Facoltà di Ingegneria

Corso di laurea specialistica in Ingegneria Informatica

Progetto e Sviluppo di un’applicazione per la gestione di

un reagentario per reagenti chimici

Relatore : Laureando :

Chiar.mo Prof. Maurizio Fermeglia Marko Paliska

Anno accademico : 2013-2014

Page 2: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

2

La teoria è quando si sa tutto e niente funziona. La pratica è quando tutto

funziona e nessuno sa il perchè. In questo caso abbiamo messo insieme la

teoria e la pratica: non c'è niente che funziona... e nessuno sa il perchè!

A.Einstien

Page 3: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

3

SOMMARIO

Sommario………………………………………………………………………………………………………………………………pag. 3

Introduzione…………………………………………………………………………………………………………………………………..4

Analisi…………………………………………………………………………………………………………………………………………….6

Progettazione (concettuale del DB)………………………………………………………………………………………………..9

Progettazione (logica del DB)……………………………………………………………………………………………………….22

Progettazione (interfaccia)……………………………………………………………………………………………………………33

Realizzazione (progettazione fisica del DB)…………………………………………………………………………………..54

Realizzazione (implementazione dell’interfaccia)…………………………………………………………………………59

Conclusioni…………………………………………………………………………………………………………………………………108

Dedica……………………………………………………………………………………………………………………………………..…109

Page 4: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

4

INTRODUZIONE

La presente tesi affronta la problematica della gestione di un reagentario. Il reagentario è il

magazzino delle sostanze chimiche che vengono utilizzate in un ente di ricerca che svolga attività

nell’ambito delle scienze chimiche, fisiche, mediche, ingegneristiche e biologiche, quindi

potenzialmente utilizzabile sia in dipartimenti universitari che in enti di ricerca.

L’analisi riportata nella tesi riguarda il reagentario del dipartimento di ingegneria ed architettura

dell’Università di Trieste, ma, poiché le norme di legge e le procedure di utilizzo dei reagenti

chimici sono relativamente standard, potrebbe essere applicato anche in altri contesti.

Le sostanza chimiche in possesso del dipartimento vengono conservate principalmente in una

stanza centrale chiamata “magazzino reagentario”. Alcune sostanze che necessitano di particolari

condizioni di stoccaggio, ad esempio temperatura costante, vengono stoccate in più frigoriferi

localizzati all'interno dei laboratori.

Il lavoro può essenzialmente dividersi in due parti. Nella prima ci siamo occupati della

progettazione dell’applicazione. Quindi il primo passo è stata la progettazione a livello puramente

teorico tenendo conto delle esigenze del utente finale, e analizzando le migliorie che si potevano

introdurre rispetto al programma già esistente. Dopo aver analizzato migliorie ed esigenze del

utente si è passati alla seconda parte, ossia lo sviluppo dell’applicazione. Qui si è realizzato tutto

ciò che era stato pianificato precedentemente: database e interfaccia.

Il risultato finale è stato un programma eseguibile (*.EXE), collegato con un DB, che gestisce tutte

le informazioni delle sostanze chimiche del reagentario. Per gestione delle sostanze chimiche si

intende la possibilità di visualizzare, inserire, modificare ed eliminare tutte le informazioni in

possesso.

La motivazione principale è stata la gestione di reagenti chimici tra più laboratori. Poter gestire in

modo intuitivo il consumo di un reagente, lo spostamento, poter ricercare in quale laboratorio si

trova un reagente, poter gestire tutte le caratteristiche che un reagente possiede e infine poter

avere un resoconto con appositi filtri di ricerca.

Il problema era già stato affrontato in via preliminare con la realizzazione di un prototipo

funzionante (“Progetto e sviluppo di un’applicazione per la gestione di un Reagentario” di Samo

Ziberna) che ha permesso ad alcuni utenti chiave di analizzare la bontà della procedura ed

evidenziare le criticità. Questa analisi ha portato alla necessità di riconsiderare la struttura della

base di dati e dell’interfaccia grafica per poter tenere conto sia delle esigenze degli utenti che delle

mutate condizioni della gestione.

Durante lo svolgimento del lavoro sono stati affrontati diversi punti essenziali. Innanzitutto il

primo punto è stato lo Studio di Tecnologie da usare. IL DIA aveva un SQL Server 2008 R2, ma è

stato aggiornato alla versione 2012. Il programma precedente era stato sviluppato in Visual Studio

2008. Quindi dati questi vincoli di progetto si è passati allo sviluppo del software mediante SQL

Page 5: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

5

Server 2012 per il DB e Visual Studio 2013 per la GUI. Questi strumenti di sviluppo sono stati

studiati negli anni accademici in diversi corsi quindi lo studio di tecnologie usate era già noto. Il

punto successivo è stata la raccolta di requisiti. Prima si sono analizzate le migliorie da fare al

programma già esistente, e poi sono state affrontate le esigenze nuove degli utenti finali. In

particolare rispetto al programma precedente è stata introdotto il concetto di “Consumo” e

“Spostamento”(eliminati i concetti di Reso e Prelievo), introdotto il consumo di tipo decimale

(prelievo di una quantità non intera), migliorata la Ricerca che ora risulta più efficiente, introdotta

la gestione degli utenti da interfaccia e la Reportistica finale. La fase successiva è stata la

progettazione del DB e della GUI in base ai requisiti raccolti. Poi si è passati ad una fase di testing

che ha consentito all’utente finale di rendersi conto delle specifiche di progetto richieste e di

eventuali ulteriori correzioni da implementare nel progetto.

Il capitolo successivo riguarda l’Analisi dove vengono evidenziati i requisiti dell’utente finale e le

migliorie da fare al programma già esistente. Il passo successivo è la progettazione concettuale,

logica del DB e la progettazione dell’interfaccia in base ai requisiti espressi in fase di Analisi.

L’ultimo passo è stata la progettazione fisica del DB (trasformazione dei schemi logici in tabelle e

programmazione degli indici) e la realizzazione dell’interfaccia (dove sono stati usati oggetti di tipo

SQL comand e datagridview per la visualizzazione dei dati).

Page 6: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

6

ANALISI

In questo capitolo viene svolto il lavoro di Analisi partendo dalla situazione preesistente

analizzando la documentazione disponibile.

Le informazioni principali raccolte si trovavano già nel DB del progetto sviluppato anni fa (Progetto

e sviluppo di un’applicazione per la gestione di un Reagentario).

In particolare erano state messe in evidenza le Frasi di Rischio e Sicurezza (in italiano e in inglese).

Frasi di rischio e di sicurezza(R\S):

Le frasi di rischio e sicurezza sono delle frasi standard, contraddistinte da un codice e una

frase in linguaggio naturale, che descrivono rispettivamente i rischi per la salute umana, animale o ambientale che

una sostanza chimica può provocare e i consigli di prudenza nel manipolare tale sostanza chimica. Le frasi sono

codificate dalla direttiva europea 88/379/CEE (e successive modifiche) e attualmente vige l'obbligo di specificarle

sulle etichette delle sostanze chimiche. Oggi vengono inglobate in file *.pdf chiamate Schede di Rischio\Sicurezza

dove ci sono tutte le informazioni su una determinata Sostanza Chimica.

Situazione preesistente

La situazione preesistente riguarda un progetto , tutto da migliorare, svolto negli anni precedenti.

Quest’ultimo è composto da un DB e da un’interfaccia sviluppata in Visual Studio in C#. Per il DB è

stato usato SQL Server (la versione integrata con Visual Studio). L’interfaccia è stata

completamente rifatta sempre in Visual Studio in C#. Ciò si è reso necessario per apportare le

modifiche richieste.

Page 7: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

7

Figura 1 : Applicazione tratta dal progetto “Progetto e sviluppo di un’applicazione per la gestione di

un Reagentario” di Samo Ziberna

Requisiti Software

Il nuovo sistema sviluppato doveva essere modificato per poter avere un uso più intuitivo e

soprattutto più semplice.

Bisogna distinguere tra gli utenti che usano l’interfaccia. Quindi si deve poter gestire le

informazioni degli utenti (credenziali con username e password) che possono essere di 3 tipi :

utente non registrato, utente registrato e administrator, ognuno con diverse possibilità di gestione

di informazioni. In caso di utenti che vengono registrati si necessitano Nome e Cognome del

utente, una password e username per accedere. Inoltre ogni utente fa parte di un Laboratorio che

usa tali sostanze.

Innanzitutto il sistema deve poter visualizzare e gestire a seconda dei casi in uso, le frasi di rischio

e sicurezza che vengono memorizzate in un file *.PDF, chiamata comunemente Scheda di

Rischio/Sicurezza che contiene tutte le informazioni della sostanza (e quindi in essa le Frasi di R\S).

La sezione deve poter essere visualizzata sia in italiano che inglese. Questa funzionalità deve

essere accessibile a chiunque. Ogni Scheda di R\S è associata ad una sostanza chimica. Ogni

sostanza chimica può avere un sinonimo e può avere una classe di appartenenza. La sostanza

chimica deve poter essere trovata da un elenco in base al nome della sostanza, al CAS number e

alla formula chimica. Ogni sostanza chimica fa parte di una determinata Classe di Sostanze. I

sinonimi hanno una fonte di informazioni (vari siti internet) ed è contradistinta da un codice. Deve

Page 8: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

8

esserci inoltre la possibilità di poter salvare in Excel tutta la lista delle sostanze chimiche. Ogni

utente può visualizzare tutte le informazioni sulle Schede di R\S, un utente User può effettuare il

Consumo e lo Spostamento della sostanza chimica ma solo l’administrator può anche gestirle

(inserimento, modifica ed eliminazione).

L’interfaccia deve poter essere in grado anche di gestire sostanze chimiche e i rispettivi reagenti

(per gestione si intende la possibilità di registrare, quindi inserire informazioni, poterle modificare

ed eventualmente eliminarle). Alcune informazioni importanti possono essere il Nome del

reagente, Capacità del contenitore, Acquirente (persona che compra la sostanza), Data di

scadenza, Data di acquisto, Quantità Residua, Stato (Disponibile, Esaurito ed Eliminato), data di

eliminazione, i dati del fornitore del sostanza chimica (Nome, Indirizzo, Fax, Telefono, E-mail) e un

Numero Progressivo (che rappresenta un’etichetta che viene messa sulla bottiglia per poterla

contradistinguere in modo univoco e semplice soprattutto nel caso ci siano inserimenti multipli).

In questo contesto distinguiamo la sezione Consumo e la sezione Spostamento. Nella sezione

Consumo si possono visualizzare le informazioni sui possibili reagenti(contenitori e contenuto

della sostanza) da consumare (si può fare una ricerca in base al Nome della sostanza, CAS number

e Formula chimica). Per eseguire il Consumo viene richiesta un’ informazione essenziale quale la

quantità da consumare (che ovviamente deve essere minore della quantità residua, si necessita di

un controllo appropiato). Le altre informazioni visualizzate sono : la capacità del contenitore, la

locazione del contenitore, l’unità di misura, l’utente che esegue l’operazione e l’acquirente (cioè la

persona che ha acquistato la sostanza).

Nella sezione Spostamento viene modificata solo la locazione. Anche quì vengono visualizzate

informazioni quali : la quantità residua, la capacità, l’unità di Misura, l’acquirente e l’utente che ha

inserito l’informazione sulla sostanza. Anche in questa sezione come nel Consumo c’è la possibilità

di ricerca, fra tutti i possibili reagenti da restituire, in base al Nome della sostanza, CAS number e

Formula Chimica. Sia l’administrator che un utente verificato possono accedere a queste

informazioni. L’administrator in più può inserire, modificare ed disabilitare i vari utenti (username

e password), può inserire, modificare ed eliminare le sostanze chimiche ed i rispettivi reagenti(per

reagenti si intendono i contenitori della sostanza e il relativo contenuto).

Inoltre deve esserci la possibilità di fare un Report, cioè un riassunto che chiamiamo Reportistica

nella quale si dove poter ricercare tutte le operazioni svolte sui reagenti. In particolare deve

esserci la possibilità di Ricercare in tutto il DB ad esempio chi ha fatto cosa, quando lo ha fatto e

che cosa ha fatto. Devono essere progettati dei opportuni filtri di ricerca in base al tipo di

operazione svolta, in base al reagente, in base al utente e in base alla data, con ovviamente

possibilità di filtri additivi.

Page 9: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

9

PROGETTAZIONE

DATABASE-progettazione concettuale

Tenuto conto dei Requisiti espressi nel capitolo di Analisi il passo successivo è stata la

progettazione del DB. Il primo passo è stata la progettazione concettuale. Partiamo dalla

situazione già esistente che è la seguente :

Gestione Frasi di R\S

Page 10: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

10

Gestione Reagenti

Possiamo già vedere da questi due schemi esistenti che ci sono delle entità e relazioni che

verranno sfruttate anche nel nuovo DB. Nella Gestione Frasi di R\S sfrutteremo l’entità Sostanza

Chimica e la relazione Dizionario che la lega con l’entità Sinonimo e con l’entità Fonte dei Sinonimi.

Nella parte Gestione Reagenti verrà sfruttato interamente ad eccezione della parte di Stoccaggio e

Scarto, inoltre verrà eliminata le relazioni di Prelievo e verrà introdotto il concetto di Consumo e

Spostamento.

Page 11: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

11

GESTIONE SOSTANZA CHIMICA :

RAGRUPPAMENTO DI FRASI

FRASI RELATIVE ALLE GESTIONE FRASI R\S Innanzitutto il sistema deve poter visualizzare e gestire a seconda dei casi in uso, le frasi di rischio e sicurezza che vengono memorizzate in un file *.PDF, chiamata comunemente Scheda di Rischio/Sicurezza che contiene tutte le informazioni della sostanza (e quindi in essa le Frasi di R\S). La sezione deve poter essere visualizzata sia in italiano che inglese. Questa funzionalità deve essere accessibile a chiunque. Ogni Scheda di R\S è associata ad una sostanza chimica. Ogni sostanza chimica può avere un sinonimo e può avere una classe di appartenenza. La sostanza chimica deve poter essere trovata da un elenco in base al nome della sostanza, al CAS number e alla formula chimica. Ogni sostanza chimica fa parte di una determinata Classe di Sostanze. I sinonimi hanno una fonte di informazioni (vari siti internet) ed è contradistinta da un codice. Deve esserci inoltre la possibilità di poter salvare in Excel tutta la lista delle sostanze chimiche.

GLOSSARIO DEI TERMINI

TERMINE DESCRIZIONE SINONIMO COLLEGAMENTO Sostanza Chimica Un corpo che

possiede proprietà chimiche e fisiche ben definite

Materia Frasi di R\S

Scheda di R\S Le frasi di rischio e sicurezza sono delle frasi standard, contraddistinte da un codice e una frase in linguaggio naturale, che descrivono rispettivamente i rischi per la salute umana, animale o ambientale che una sostanza chimica può provocare e i consigli di prudenza nel manipolare tale sostanza chimica.

Pericolosità, Frasi di R\S

Sostanza Chimica

Classe L'approccio più classico allo studio della chimica organica consiste nel raggruppare i composti in classi di sostanze che presentano un medesimo gruppo funzionale,

Gruppo Sostanza Chimica

Page 12: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

12

definendo così una serie omologa. I composti che fanno parte di una stessa classe possiedono la stessa composizione e le stesse proprietà chimiche, mentre le loro proprietà chimico-fisiche variano in funzione della massa molecolare.

Sinonimo Definisce una sostanza chimica con le stesse proprietà chimico-fisiche soltano con termine diverso.

Sostanza Chimica

ANALISI DI ENTITÀ E RELAZIONI

Per identificare lo schema scheletro vediamo che ci sono 2 enitità essenziali : la sostanza chimica e

Sinonimi, che vengono unite dalla relazione Dizionario.

SOSTANZA CHIMICA DIZIONARIO SINONIMO

Figura 2 : Schema scheletro

Analizzando attentamente i requisiti possiamo espandere varie entità e relazioni in base ai

requisiti sopra espressi.

L’entità Sinonimo a sua volta viene unita all’entità Fonte dei Sinonimi con la relazione Sorgente.

Page 13: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

13

SOSTANZA CHIMICA DIZIONARIO SINONIMO

SORGENTE

FONTE DEI SINONIMI

Figura 3 : Aggiunta di Entità e Relazioni intorno alla Sostanza Chimica

Raggruppando il tutto si ottiene lo schema E-R :

SOSTANZA CHIMICA

DIZIONARIO

SINONIMO

SORGENTEFONTE DEI SINONIMI

Figura 4 : Schema E-R nella Gestione Frasi R\S

ANALISI DI ATTRIBUTI E CARDINALITÀ

Ora andiamo ad analizzare gli attributi in base ai requisiti espressi.

Lo schema scheletro si compone dei seguenti attributi :per la Sostanza Chimica distinugiamo

IDSostanzaChimica, CAS, NomeSostanza, MassaMolecolare, Classe e Formula. Per le cardinalità si

osserva che l’entità Sostanza Chimica e unita alla relazione Dizionario con la cardinalità uno-molti

(0-N). Mentre la cardinalità tra la relazione Dizionario e Sinonimo è uno-molti (1-N). Quindi la

Page 14: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

14

cardinalità che legherà le 2 entità Sostanza Chimica e Sinonimo sarà del tipo 1-N, cioè per per 1

sostanza chimica possiamo avere più sinonimi.

SINONIMODIZIONARIOSOSTANZA CHIMICA

CAS

Massa Molecolare Formula

Classe NomeSostanza

Sinonimo

1-N

Figura 5 : Schema Scheletro con attributi e cardinalità

Per l’entità Fonte dei Sinonimi abbiamo NomeFonte e urlFonte. La cardinalità che unisce l’entità

Sostanza chimica alla relazione Dizionario è del tipo 0-N mentre l’entità Sinonimo con la relazione

Dizionario è unita da una cardinalità del tipo 1-1.

SINONIMO

Sinonimo

SORGENTE

FONTE DEI SONINIMI

NomeFonte

urlFonte

0-1

1-N

Figura 6 : Parte del diagramma E-R riguardante i Sinonimi e Fonte dei Sinonimi con attributi e

cardinalità

Page 15: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

15

Alla fine così otteniamo il diagramma E-R finale con attributi e cardinalità riguardante la gestione

Sostanza Chimica.

SOSTANZA CHIMICA

CAS

Massa Molecolare

Formula

Classe NomeSostanza

FONTE DEI SINONIMISORGENTESINONIMO

0-1 1-N

urlFonte

Sinonimo

DIZIONARIO

0-N

1-1

NomeFonte

Figura 7 : Diagramma E-R finale della gestione Sostanza Chimica

GESTIONE REAGENTI (CONTENITORI e CONTENUTO)

RAGRUPPAMENTO DI FRASI

FRASI RELATIVE ALLE GESTIONE REAGENTI Ogni utente può visualizzare tutte le informazioni sulle Schede di R\S, un utente User può effettuare il Consumo e lo Spostamento della sostanza chimica ma solo l’administrator può anche gestirle (inserimento, modifica ed eliminazione). L’interfaccia deve poter essere in grado anche di gestire sostanze chimiche e i rispettivi reagenti (per gestione si intende la possibilità di registrare, quindi inserire informazioni, poterle modificare ed eventualmente eliminarle). Alcune informazioni importanti possono essere il Nome del reagente, Capacità del contenitore, Acquirente (persona che compra la sostanza), Data di scadenza, Data di acquisto, Quantità Residua, Stato (Disponibile, Esaurito ed Eliminato), data di eliminazione, i dati del fornitore del sostanza chimica (Nome, Indirizzo, Fax, Telefono, E-mail) e un Numero Progressivo (che rappresenta un’etichetta che viene messa sulla bottiglia per poterla contradistinguere in modo univoco e semplice soprattutto nel caso ci siano inserimenti multipli). In questo contesto distinguiamo la sezione Consumo e la sezione Spostamento. Nella sezione Consumo si possono visualizzare le informazioni sui possibili reagenti(contenitori e contenuto della sostanza) da consumare (si può fare una ricerca in base al Nome della sostanza, CAS number

Page 16: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

16

e Formula chimica). Per eseguire il Consumo viene richiesta un’ informazione essenziale quale la quantità da consumare (che ovviamente deve essere minore della quantità residua, si necessita di un controllo appropiato). Le altre informazioni visualizzate sono : la capacità del contenitore, la locazione del contenitore, l’unità di misura, l’utente che esegue l’operazione e l’acquirente (cioè la persona che ha acquistato la sostanza). Nella sezione Spostamento viene modificata solo la locazione. Anche quì vengono visualizzate informazioni quali : la quantità residua, la capacità, l’unità di Misura, l’acquirente e l’utente che ha inserito l’informazione sulla sostanza. Anche in questa sezione come nel Consumo c’è la possibilità di ricerca, fra tutti i possibili reagenti da restituire, in base al Nome della sostanza, CAS number e Formula Chimica. Sia l’administrator che un utente verificato possono accedere a queste informazioni. L’administrator in più può inserire, modificare ed disabilitare i vari utenti (username e password), può inserire, modificare ed eliminare le sostanze chimiche ed i rispettivi reagenti(per reagenti si intendono i contenitori della sostanza e il relativo contenuto). Inoltre deve esserci la possibilità di fare un Report, cioè un riassunto che chiamiamo Reportistica nella quale si dove poter ricercare tutte le operazioni svolte sui reagenti. In particolare deve esserci la possibilità di Ricercare in tutto il DB ad esempio chi ha fatto cosa, quando lo ha fatto e che cosa ha fatto. Devono essere progettati dei opportuni filtri di ricerca in base al tipo di operazione svolta, in base al reagente, in base al utente e in base alla data, con ovviamente possibilità di filtri additivi.

GLOSSARIO DEI TERMINI

TERMINE DESCRIZIONE

SINONIMO COLLEGAMENTO

Utente Personaggio che usa l’interfaccia per scopi quali la gestione (osservare, modificare ed eliminare) delle informazioni. Può essere di 3 tipi : utente sconosciuto (personaggio con informazioni non memorizzate nel DB), utente di Laboratorio (personaggio provvisto di

Personaggio Consumo, Spostamento, Laboratorio,Fornitore

Page 17: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

17

username e password che si autentica e che può gestire le informazioni rigaurdanti le Frasi di R\S e può prelevare e\o restituire un reagente-contenitore) e administrator (personaggio che può fare tutto, cioè gestire le informazioni degli utenti, dei reagenti, delle sostanze chimiche e delle frasi di R\S).

Consumo\Spostamento

Azione che un utente compie.

Consumo\Spostamento della sostanza

Utente,Reagente

Reagente In questo contesto il Reagente sta ad indicare fisicamente un contenitore nel quali vengono messi determinate sostanze chimiche.

Contenitore Utente,Spostamento,Locazione

Fornitore Altro personaggio dal quale si compra una determinata sostanza chimica. Questa stessa sostanza chimica poi viene messa in un contenitore

Venditore Utente, Reagente

Page 18: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

18

(reagente). Laboratorio Parte

dell’università dove si eseguono vari esperimenti usando le sostanze chimiche. Ogni utente registrato fa parte di un laboratorio.

Stanze Utente

ANALISI DI ENTITÀ E RELAZIONI

Possiamo distinguere 2 entità fondamentali : l’entità utente, e l’entità reagente unite dalla

relazione Azione che poi sarà il Consumo e Spostamento rispettivamente.

UTENTE AZIONE REAGENTE

Figura 8 : Schema scheletro nella Gestione Reagenti

In base ai requisiti sopra espressi possiamo espandere ed ottenere le seguenti nuove entità e

relazioni.

L’entità Utente sarà unita da una relazione Appartenenza con l’entità Laboratorio e la stessa entità

Utente sarà unita con l’entità Fornitore dalla relazione Acquisto.

Page 19: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

19

UTENTE APPARTENENZA LABORATORIO

ACQUISTO

FORNITORE

Figura 9 : Diagramma E-R tra Utente e Laboratorio e Fornitore

Quindi possiamo dividere la relazione Azione nel Consumo e\o Spostamento e Eliminazione che

vengono eseguite e sono operazioni lecite.

Dai requisiti possiamo notare la necessità di inserimento di una nuova entità chiamata Operazione

e di una relazione chiamata Traccia.

REAGENTE TRACCIA OPERAZIONE

Figura 10 : Diagramma E-R tra Reagente e Operazione

Alla fine abbiamo lo schema E-R finale nella Gestione Reagenti.

Page 20: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

20

UTENTE

APPARTENENZA

LABORATORIO ACQUISTO

FORNITORE

REAGENTECONSUMO\

SPOSTAMENTO

ELIMINAZIONE

TRACCIAOPERAZIONE

Figura 11 : Diagramma E-R finale della Gestione Reagenti (Contenitori)

ANALISI DI ATTRIBUTI E CARDINALITÀ

In base ai requisiti espresso abbiamo i seguenti attributi.

Per lo schema scheletro osserviamo gli attributi : l’entità Utente ha gli attributi Username(PK),

Password, NomeUtente e CognomeUtente; l’entità Reagente ha gli attributi DataAcquisto, Data

Eliminazione, Quantità Residua, Username, Capacità, Unità di Misura, DataScadenza, Locazione e

Progressivo.

Per quel che riguarda le cardinalità l’entità Utente e la relazione Consumo e Spostamento e l’entità

Reagente hanno una cardinalità 1-1 .

UTENTE REAGENTECONSUMO\

SPOSTAMENTO

Username

Password

NomeUtente

CognomeUtente

Username

DataAcquisto DataEliminazione

DataScadenza Capacità Username

QuantitàResidua

1-1

Locazione

Unità di Misura

Abilitazione

ELIMINAZIONE

Progressivo

1-1

Acquirente

Figura 12 : Schema scheletro della Gestione Reagenti con attributi e cardinalità

Analizzando le altre entità della Gestione Reagenti possiamo notare i seguenti attributi : per

l’entità Laboratorio abbiamo NomeLaboratorio; per l’entità Fornitore abbiamo NomeFornitore,

Page 21: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

21

Indirizzo, Telefono, Fax e Email. Per la tabella Operazione abbiamo i seguenti attributi :

Operazione, Data e Locazione Passata.

Le cardinalità invece riscontrate sono : tra l’entità Laboratorio e la relazione Appartenenza

abbiamo una 0-N, mentre tra la relazione Appartenenza e l’entità Utente 1-1; tra l’entità Utente e

quella Fornitore abbiamo una relazione Acquisto che le unisce con una cardinalità 0-N; l’entità

Reagente e al relazione Acquisto hanno una cardinalità 1-1. La cardinalità che unisce l’entità

Reagente con l’entità Operazione è 1-N.

UTENTE APPARTENENZA LABORATORIO

ACQUISTO

FORNITORE

NomeLaboratorio

Nome

Indirizzo

Telefono

Fax

Email

1-1N-0

0-N REAGENTE

1-1

OPERAZIONE

TRACCIA

1-N

Operazione

Data

Locazione Passata

Figura 13 : Diagramma E-R tra Utente e Laboratorio e Fornitore con attributi e cardinalità

Alla fine così possiamo ottenere lo schema finale E-R con attributi e cardinalità.

Page 22: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

22

Figura 14 : Schema finale E-R della Gestione Reagenti

DATABASE-progettazione logica

Dopo aver svolto la progettazione concettuale passiamo a quella logica. Primo passo definiamo la

Tavola dei Volumi.

GESTIONE SOSTANZA CHIMICA

TAVOLA DEI VOLUMI

Una possibile tavola dei volumi è la seguente

CONCETTO TIPO VOLUME Sostanza Chimica E 1000

Sinonimo E 106

Fonte dei Sinonimi E 15

UTENTE REAGENTECONSUMO\

SPOSTAMENTO

Username

Password

NomeUtente

CognomeUtente

DataAcquisto DataEliminazione

DataScadenzaCapacità

Username

QuantitàResidua

Locazione

Unità di Misura

APPARTENENZA

LABORATORIO ACQUISTO

FORNITORE

NomeLaboratorio

Nome

Indirizzo

Telefono

Fax

Email

1-10-N

1-1

0-N

Abilitazione

ELIMINAZIONE

1-1

1-1

Progressivo

TRACCIA

OPERAZIONE

oPERAZIONE

dATALocazione Passata

1-N

Acquirente

Page 23: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

23

TAVOLA DELLE OPERAZIONI E DEGLI ACCESSI

Analizzando lo schema concettuale , possiamo simulare il funzionamento del DB e quindi proporre

una possibile tavola delle operazioni e degli accessi. Ogni Sostanza Chimica può avere più di 1

Sinonimo così come la Fonte può essere più di 1.

Una possibile tavola delle operazioni può essere la seguente :

OPERAZIONE TIPO FREQUENZA Ricerca di una Sostanza Chimica

L 10 volte al giorno

Inserimento di un nuovo Sinonimo di una Sostanza

S 1 volta a settimana

Inserimento di una nuova Sostanza Chimica

S 1 volta a settimana

Inserimento nuova Fonte dei Sinonimi

S 1 volta a settimana

Per quel che riguarda la ricerca di una sostanza chimica possiamo ad esempio avere una seguente

tabella degli accessi :

CONCETTO COSTRUTTO ACCESSI TIPO Sostanza Chimica Entità 1 L

Sinonimo Entità 3 L

Fonte dei sinonimi Entità 2 L

Ovviamente la stessa tavola può essere fatta nel caso in cui inseriamo i dati, questo caso il tipo di

operazione sarebbe quello di scrittura.

Ad esempio se eseguiamo un inserimento di una nuova sostanza chimica, possiamo avere una

tabella degli accessi come la seguente :

CONCETTO COSTRUTTO ACCESSI TIPO Sostanza Chimica Entità 1 S

Sinonimo Entità 1 S

Fonte dei sinonimi Entità 2 S

Page 24: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

24

RISTRUTTURAZIONE DELLO SCHEMA E-R

PARTIZIONAMENTO\ACCORPAMENTO DI ENTITÀ E RELAZIONI

Ora vediamo dei ulteriori possibili cambiamenti per ottimizzare lo schema E-R finale nella Gestione

Sostanza Chimica. Analizziamo l’attributo Classe. Infatti lo possiamo pensare come un’entità

separata ed unito con la relazione Classe-Sostanza con cardinalità 1-1.

Tenuto conto delle considerazioni, possiamo ottenere il seguente schema E-R ristrutturato

SOSTANZA CHIMICA

DIZIONARIO

SINONIMO

SORGENTE

FONTESinonimo

NomeFonte

urlFonte

1-N

1-N

SOSTANZA CHIMICA

CAS

Massa Molecolare

Formula

NomeSostanza

CLASSE-SOSTANZA

CLASSE

1-1

Classe

Figura 15 : Schema E-R della Gestione Sostanza Chimica ristrutturato

Page 25: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

25

SCELTA DEGLI IDENTIFICATORI PRIMARI

Questa parte è l’ultimo ritocco allo schema E-R prima della traduzione verso il modello logico. Ogni

entità ha una sua chiave primaria che la identifica. Così facendo lo schema E-R è il seguente (le

chiavi primarie PK sono contrassegnate di rosso) :

SOSTANZA CHIMICA

DIZIONARIO

SINONIMO

SORGENTE

FONTE

Sinonimo

NomeFonte

urlFonte

1-N1-N

SOSTANZA CHIMICA

CAS

Massa Molecolare

Formula

Classe

NomeSostanzaIDSostanza Chimica

IDSinonimo

IDFonte

CLASSE-SOSTANZA

CLASSE

1-1

Classe

IDClasse

Figura 16 : Schema E-R ristrutturato con PK

SCELTA DEI VINCOLI DI INTEGRITÀ REFERENZIALE

La relazione Dizionario invece verrà eliminata e verrà inserita la chiave esterna nell’entità

Sinonimo (IDSostanzaChimica). Anche la relazione Sorgente sarà eliminata e nell’entità Sinonimo

verrà inserita la chiave esterna IDSinonimoFonte che la collegherà all’entità Fonte e la chiave

esterna IDSostanzaChimica per collegarla con l’entità SostanzaChimica.

Page 26: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

26

LEGGENDA:

chiave primaria

chiave esterna

SOSTANZA CHIMICA

Codice Frasi di Rischio

Codice Frasi di Sicurezza

DIZIONARIO

SINONIMO

SORGENTE

FONTE

Sinonimo

NomeFonte

urlFonte

0-N

1-1

0-1

1-N

SOSTANZA CHIMICA

CAS

Massa Molecolare

Formula

NomeSostanzaIDSostanza Chimica

IDSinonimo

IDFonte

Classe-Sostanza

Classe

1-1

IDClasse

Classe

IDClasse

IDSostanza ChimicaIDSinonimoFonte

Figura 17 : Schema concettuale ristrutturato con chiavi primarie e esterne della Gestione Sostanza

Chimica

Page 27: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

27

GESTIONE REAGENTI

TAVOLA DEI VOLUMI

Una possibile tavola dei volumi è la seguente

CONCETTO TIPO VOLUME Utente E 6

Laboratorio E 6

Fornitore E 6

Reagente E 500 Operazione E 100

TAVOLA DELLE OPERAZIONI E DEGLI ACCESSI

Analizzando lo schema concettuale , possiamo simulare il funzionamento del DB e quindi proporre

una possibile tavola delle operazioni e degli accessi. Ogni Utente con delle credenziali fa parte di

un Laboratorio (sia questo utente registrato o administrator) e può eseguire uno Spostamento e\o

Consumo. Solo l’administrator può inserire nuovi dati sul fornitore e sul reagente (nuovo

contenitore e contenuto).

Supponiamo di essere un’utente registrato con account User con delle credenziali valide (inserite

da un administrator). Una possibile tavola delle operazioni può essere la seguente :

OPERAZIONE TIPO FREQUENZA 1) Consumo :Prelievo di

una quantità da un contenitore di una sostanza chimica.

S 1 volta al mese

2) Spostamento : cambio di locazione del contenitore e contenuto.

S 1 volta alla settimana

Per quel che riguarda l’operazione n.1 possiamo ad esempio avere una seguente tabella degli

accessi :

CONCETTO COSTRUTTO ACCESSI TIPO Consumo Relazione 1 L

Reagente Entità 1 S

Sostanza Chimica Entità 1 L

Operazione Entità 1 S

Page 28: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

28

Il reagente e la sostanza chimica servono in questa operazione come dati di supporto.

Un’altra operazione molto comune può essere l’operazione n.2 cioè lo Spostamento In questo

caso una possibile tavola degli accessi è la seguente :

CONCETTO COSTRUTTO ACCESSI TIPO Spostamento Relazione 1 L

Reagente Entità 1 S

Sostanza Chimica Entità 1 L

Operazione Entità 1 S

Nel caso del administrator (che può fare tutto) invece una possibile tavola delle operazioni è la

seguente :

OPERAZIONE TIPO FREQUENZA 1) Consumo : prelievo di

una quantità da un contenitore di una sostanza chimica.

S 1 volta al mese

2) Spostamento S 1 volta ogni 2mesi

3) Inserimento dati nuovi utenti

S 1 volta all’anno

4) Inserimento dati nuovo Reagente (Contenitore e contenuto)

S 1 volta all’anno

5) Inserimento dati nuovo Fornitore

S 1 volta all’anno

Le operazioni n.1,2 e sono state descritte sopra e sono le medesime anche nel caso administrator.

L’operazione n.3 può portare ad una tavola degli accessi come la seguente :

CONCETTO COSTRUTTO ACCESSI TIPO Utente Entità 1 S Laboratorio Entità 1 L

Page 29: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

29

L’operazione n.4 invece può portare ad una tavola degli accessi seguente :

CONCETTO COSTRUTTO ACCESSI TIPO Reagente Entità 1 S

Locazione Entità 1 L

Fornitore Entità 1 L

Operazione Entità 1 S

L’operazione n.5 invece può avere una tavola degli accessi come la seguente :

CONCETTO COSTRUTTO ACCESSI TIPO Fornitore Entità 1 S

RISTRUTTURAZIONE DELLO SCHEMA E-R

PARTIZIONAMENTO\ACCORPAMENTO DI ENTITÀ E RELAZIONI

Come prima cosa vediamo la necessità di scomporre l’entità Reagente. Dallo schema E-R finale

della Gestione Reagenti notiamo la relazione Acquisto tra le entità Reagente e Fornitore. Dai

requisiti sopra espresso abbiamo la necessità di distinguere 2 entità separate : così otteniamo

l’entità ReagenteDF (dati fissi cioè riguarda il vero e proprio contenitore) e ReagenteDV (dati

variabili cioè il vero e proprio prodotto chimico fisicamente presente nel contenitore). All’entità

ReagenteDF verranno assegnati gli attributi di un vero e proprio contenitore (Nome Reagente,

Capacità, Data scadenza, Data eliminazione, Data acquisto) mentre all’entità ReagenteDV vengono

assegnati gli attributi seguenti : quantità residua, stato e locazione. Le due entità vengono unite

dalla relazione RDV-DF. La relazione Acquisto si collega con l’entità ReagenteDF. Tenuto conto dei

seguenti cambiamenti lo schema E-R finale ristrutturato per la Gestione Reagenti diventa il

seguente :

Page 30: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

30

UTENTE REAGENTEDFCONSUMO\

SPOSTAMENTO

Username

Password

NomeUtente

CognomeUtente

DataAcquistoDataEliminazion

e

DataScadenza Capacità

QuantitàResidua

N-0

Unità di Misura

APPARTENENZA

LABORATORIO ACQUISTO

FORNITORE

NomeLaboratorio

Nome

Indirizzo

Telefono

Fax

Email

1-10-N

1-1

0-N

RDF-DV

REAGENTEDV

1-1

1-1

ELIMINAZIONE

1-1

N-0

Stato

Locazione

1-1

TRACCIA

OPERAZIONEOperazione

Data Locazione passata

N-1Acquirente

Figura 18 : Schema E-R della Gestione Reagenti ristrutturato

SCELTA DEGLI IDENTIFICATORI PRIMARI

Questa parte è l’ultimo ritocco allo schema E-R prima della traduzione verso il modello logico. Ogni

entità ha una sua chiave primaria che la identifica. Così facendo lo schema E-R è il seguente (le

chiavi primarie PK sono contrassegnate di rosso) :

Page 31: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

31

UTENTE REAGENTEDFSPOSTAMENTO\

CONSUMO

Username

Password

NomeUtente

CognomeUtente

DataAcquisto DataEliminazione

DataScadenza Capacità Username

QuantitàResidua

N-0Unità di Misura

APPARTENENZA

LABORATORIO

ACQUISTO

FORNITORE

NomeLaboratorio

Nome

Indirizzo

Telefono

Fax

Email

1-10-N

1-1

0-N

RDF-DV

REAGENTEDV

IDReagenteDF

IDReagenteDV

IDLaboratorio

IDFornitore

1-1

1-1

ELIMINAZIONE

1-1

N-0

Stato

Locazione

1-1

Abilitazione

OPERAZIONE

IDOperazione

Operazione

Data

Locazione passata

TRACCIA

N-1

Acquirente

Figura 19 : Schema E-R della Gestione Reagenti ristrutturato con PK

SCELTA DEI VINCOLI DI INTEGRITÀ REFERENZIALE

Prima di analizzare i vincoli di integrità referenziale abbiamo la necessità di scomporre l’entità

ReagenteDV in altre 2 entità separate. Una sarà l’entità Stato (ed indicherà se la sostanza chimica

è Disponibile, Esaurita(consumata tutta la quantità) o Eliminata (smaltita per qualche motivo)) e

l’altra sarà l’entità Locazione (cioè il luogo dove si trova). La cardinalità che si trova scomponendo

questa entità è la seguente : tra l’entità Locazione e la nuova relazione Presenza (che non verrà

mentenuta) abbiamo una cardinalità di 0-N, e tra la relazione Presenza e l’entità ReagenteDV 1-1 ;

tra l’entità ReagenteDV e la relazione Stato-ReagenteDV 1-1 e tra la stessa relazione e l’entità

Stato 1-1. Con questa scomposizione possiamo assegnare le chiavi esterne. Nell’entità

ReagenteDV abbiamo 2 chiavi esterne : IDStato (per collegarla all’entità Stato) e IDLocazione(per

collegarla all’entità Locazione). Nell’entità ReagenteDF abbiamo le seguenti chiavi esterne :

IDFornitore (per collegarla all’entità Fornitore) ,IDMisura (per collegarla all’entità Unità di Misura)

e Username(per collegarla all’entità Utente-serve per tenere traccia di chi ha inserito

l’informazione). Qui la chiave primaria dell’entità ReagenteDV fa anche da chiave esterna per

collegarla all’entità ReagenteDF, e anche la chiave primaria dell’entità ReagenteDF fa da chiave

esterna per collegarla con l’entità ReagenteDV (questo a causa della scomposizione dell’entità

REAGENTE e cardinalità 1-1 presente). Un’altra scomposizione molto utile arriva nell’entità

Utente. Infatti possiamo pensare ad un’entità Abilitazione separata dall’entità Utente. Questa

entità serve per capire se un utente registrato è un administrator, un utente normale con

Page 32: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

32

credenziali abilitato ad eseguire il consumo\spostamento. Così nell’entità Utente ci troviamo una

chiave esterna IDAbilitazione (serve per collegarsi con la tabella Abilitazione) e IDLaboratorio

(serve per collegarsi con la tabella Laboratorio). Le altre relazioni non vengono mantenute, di

conseguenza lo schema logico diventa il seguente.

LEGGENDA:

chiave primaria

chiave esterna

UTENTE REAGENTEDFCONSUMO\

SPOSTAMENTO

Username

Password

NomeUtente

CognomeUtente

DataAcquisto DataEliminazione

DataScadenza Capacità Username

QuantitàResidua

N-0APPARTENENZA

LABORATORIO

ACQUISTO

FORNITORE

NomeLaboratorio

Nome

Indirizzo

Telefono

Fax

Email

1-10-N

1-1

0-N

RDF-DV

REAGENTEDV

IDReagenteDF

IDReagenteDV

IDLaboratorio

IDFornitore

1-1

1-1

ELIMINAZIONE

1-1

N-0

Stato

Locazione

1-1

REAGENTEDF-UNITA

UNITA DI MISURA

IDUnitàDiMisura

Misura

1-1

1-1

REAGENTEDV-STATO

STATO

IDStato

PRESENZA

1-1

LOCAZIONE

IDLocazione

0-N

UTENTE-ABILIATZIONE

ABILITAZIONE

IDAbilitazione

Abilitazione

1-1

1-1

1-1

1-1

IDAbilitazione

IDLaboratorio

IDLocazione

IDStato

IDMisura

IDFornitore

TRACCIA

OPERAZIONE

N-1

Username

IDreagenteDV

IDOperazione Data

Operazione

Locazione passata

Acquirente

Figura 20 : Schema concettale ristrutturato con chiavi primarie e esterne della Gestione Reagenti

Page 33: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

33

INTERFACCIA

L’interfaccia è stata fatta seguendo in modo dettagliato tutti i Requisiti che sono stati espressi in

fase di Analisi. L’interfaccia è di tipo Windows Form. Di seguito viene riportato un possibile

diagramma di utilizzo dell’applicazione.

Inizializzazione Utente

Consumo\Spostamento

Reportistica

Gestione Reagente

Gestione Sostanza Chimica

Gestione Utenti

UTENTE REGISTRATO

ADMINISTRATOR

PERSONAGGIO QUALSIASI

Figura 21: Diagramma di utilizzo dell’applicazione

Inizializzazione Utenti

Intanto distinguiamo 3 tipi di personaggi : utente qualsiasi, utente registrato e administrator. Ogni

tipo di personaggio deve poter visualizzare le schede di Rischio e di Sicurezza di una sostanza

chimica (se questa sostanza in effetti ne è provvista). L’utente qualsiasi non può fare altro, mentre

per un utente registrato e l’administrator possono fare anche altre cose. Ciò comporta

l’inserimento di un sistema in grado di poter distinguere tra i diversi personaggi, cioè una

schermata di LogIn. Questa è la prima parte e possiamo chiamarla Inizializzazione Utenti cioè

distinguiamo i 3 tipi di personaggi che possono venir coinvolti.

Questa parte è formata da 2 windows form. Per permettere una migliore navigazione da un form

all’altro è stato sfruttato il meccanismo a schede chiamato TabControl. Quindi abbiamo 2 schede :

una per la visualizzazione e ricerca delle Sostanze Chimiche e delle relative Schede di

Rischio\Sicurezza e l’altra per effettuare il meccanismo di LogIn.

Page 34: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

34

Rischio \ Sicurezza

Schede di Rischio\Sicurezza

ADMINISTRATOR

UTENTE QUALSIASI

UTENTE REGISTRATO

LogIn

Autenticazione

Save to Excel

Ricerca in base a CAS,Nome,Formula

Username & Password

UTENTE REGISTRATO

ADMINISTRATOR

Figura 22 : Inizializzazione Utenti

Consumo\Spostamento

Questa parte può essere raggiunta solo da un’utente registrato o administrator. Qui abbiamo le

seguenti schede : Rischio\Sicurezza (la stessa con vista nella visualizzazione utenti), Consumo

(dove si memorizzano i dati di consumo) e Spostamento (si memorizzano i dati di spostamento) e

LogOut.

Page 35: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

35

Rischio \ Sicurezza

Schede di Rischio\Sicurezza

ADMINISTRATOR

UTENTE REGISTRATO

LogOut

Save to Excel

Ricerca in base a CAS,Nome,Formula

Ritorno all�Inizializzazione

Utenti

Consumo

Visualizzazione di informazioni relative al Consumo

Spostamento

Visualizzazione di informazioni relative allo Spostamento

Ricerca in base a CAS,Nome,Formula

Ricerca in base a CAS,Nome,Formula

Prelievo Reagente

Restituzione Reagente

Inserimento Dati

Inserimento Dati

Figura 23 : Consumo\Spostamento

Page 36: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

36

Gestione Utenti

Nella Gestione Utenti, raggiungibile solo da un administrator, quest’ultimo può modificare le

credenziali di un’utente, inserire un nuovo utente ed disabilitarlo (non eliminarlo in quanto

relative azioni compiute sono state ragistrate e possono essere utili a fini di ricerche ben precise

nella Reportistica).

ADMINISTRATORGestione Utenti

Visualizzazione di tutte le informazioni degli utenti

Nuovo Utente

Modifica Utente

Disabilita Utente

Figura 24 : Gestione Utenti

Page 37: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

37

Gestione Sostanza Chimica

Questa parte viene raggiunta solo da un administrator. Questa scheda permette di : Ricercare Una

sostanza chimica in base al CAS, Nome e Formula, Gestire una Sostanza Chimica (per gestire si

intende Aggiungere, Modificare e Eliminare) e Gestire i Sinonimi..

ADMINISTRATOR

Gestione Sostanza Chimica

Visualizzazione di tutte le informazioni delle sostanze chimiche, inclusi Sinonimi.

Nuova Sostanza Modifica Sostanza Elimina Sostanza

Nuovo Sinonimo Modifica Sinonimo Elimina Sinonimo

Ricerca in base a CAS,Nome,Formula

Save in Excel

Figura 25 : Gestione Sostanza Chimica

Page 38: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

38

Gestione Reagente

In questa parte l’administrator può ricercare sempre la sostanza chimica desiderata in base al

Nome, CAS e Formula. Poi in base alla sostanza chimica scelta, si visualizza il contenitore con il

contenuto corrispondente e lo stato della sostanza (Disponibile, Esaurito, Eliminato). Inoltre in

questa scheda c’è la possibilità di inserire i dati di un Fornitore.

ADMINISTRATOR

Gestione Reagenti

Visualizzazione di tutte le informazioni dei Reagenti

Ricerca in base a CAS,Nome,Formula

Ricerca in base allo stato del Reagente

Nuovo Reagente

Modifica Reagente

Elimina ReagenteSave in Excel

Nuovo Fornitore

Inserimento dati

Figura 26 : Gestione Reagenti

Traduzione Italiano-Inglese

Dall’analisi dei Requisiti si deduce che c’è bisogno di una possibilità di visualizzazione in Inglese.

Quindi con un semplice click si può passare alla traduzione dell’intera interfaccia e dei dati dal DB.

Questo vale per qualsiasi personaggio stia agendo e in qualsiasi momento lo si desideri su qualsiasi

scheda si stia operando.

Diagramma UML delle classi

Se analizziamo il diagramma di utilizzo possiamo per ogni form che è stato creato analizzare il

diagramma delle classi create in UML.

Page 39: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

39

Inizializzazione Utenti

Qui abbiamo 1 form (Form1) e 2 schede. Il Form1 è formato dai seguenti oggetti e metodi :

Figura 27

Page 40: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

40

Consumo\Spostamento

Qui abbiamo 1 form (Form2) e fino a un massimo di 7 (in base all’utente) schede. Il Form2 è

formato dai seguenti oggetti, metodi e proprietà :

Figura 28

Page 41: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

41

Poi in base alla figura 24 distinguiamo il Form3 necessario per l’inserimento dei dati di Consumo . Il

Form3 è formato dai seguenti oggetti, metodi e proprietà :

Figura 29

Page 42: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

42

Il Form4 invece riguarda lo Spostamento. Il Form ha i seguenti metodi, oggetti e proprietà :

Figura 30

Page 43: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

43

Gestione Reagente

Il form5 invece serve per modificare i dati di un reagente (contenitore). Il form ha i seguenti

metodi, proprietà ed oggetti :

Figura 31

Page 44: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

44

Invece il Form6 serve eventualmente per inserire dati di un nuovo Fornitore. Questo Form ha i

seguenti metodi, oggetti e proprietà :

Figura 32

Mentre il seguente Form8 server per Eliminare il reagente selezionato. Oggetti, metodi e proprietà

sono i seguenti :

Page 45: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

45

Figura 33

Il Form 7 server invece per Inserire i dati di un nuovo Reagente. Il Form ha i seguenti oggetti,

metodi e proprietà :

Page 46: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

46

Figura 34

Page 47: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

47

Gestione Sostanza Chimica

Il Form9 invece server per aggiungere un nuovo Sinonimo ad una sostanza chimica. Oggetti,

metodi e proprietà sono i seguenti :

Figura 35

Il Form10 invece server per inserire eventualmente i dati di una nuova Fonte. Oggetti, metodi e

proprietà sono i seguenti :

Page 48: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

48

Figura 36

Il Form11 invece serve per Modificare i dati di un Sinonimo di una sostanza chimica. Oggetti,

metodi e proprietà sono i seguenti :

Page 49: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

49

Figura 37

Il Form 12 invece server per l’inserimento dei dati di una nuova sostanza chimica. Oggetti, metodi

e proprietà sono i seguenti :

Page 50: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

50

Figura 38

Salva dati in Excel

Il Form CopiaExcel è un form creato per far aspettare l’utente, in modo standard, durante un

salvataggio da una griglia con molti dati ad un foglio Excel. Ogetti e metodi sono i seguenti :

Figura 39

Page 51: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

51

Gestione Utenti

In questa scheda invece vengono gestite e informazioni degli utenti. Oggetti, metodi e proprietà

sono i seguenti :

Figura 40

Page 52: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

52

Informazioni

Quest’ultimo Form contiene solo le informazioni sull’autore del programma. Oggetti, metodi e

proprietà sono i seguenti :

Figura 41

Schema finale

Di conseguenza possiamo ottenere lo schema finale che è il seguente :

Gestione Sostanza Chimica

Gestione Reagenti Gestione Utenti

Consumo\Spostamento

Info

Salvataggio su Excel

Page 53: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

53

REALIZZAZIONE

DATABASE-progettazione fisica

Dalla progettazione logica con lo schema con chiavi primarie e esterne si arriva allo schema fisico

che rappresenta in modo fedele la progettazione del DB. Prima analizziamo le 2 parti separate per

poi trovare un punto d’incontro e unire il tutto.

GESTIONE SOSTANZA CHIMICA

Dall’ultimo schema della progettazione logica possiamo ottenere questo schema della

progettazione fisica.

tblSostanzaChimica

NomeSostanza

IDSostanzaChimicaPK

IDClasseFK

CAS

MassaMolecolare

Formula

tblClasse

IDClassePK

Classe

tblSinonimo

IDSinonimoPK

IDSostanzaChimicaFK

Sinonimo

IDSinonimoFonteFK

tblFonte

IDFontePK

NomeFonte

urlFonte

Figura 42 : Schema fisico Gestione Sostanza Chimica

Page 54: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

54

GESTIONE REAGENTI

Dall’ultimo schema della progettazione logica possiamo ottenere questo schema della

progettazione fisica.

tblUtente

NomeUtente

UsernamePK

IDLaboratorioFK

CognomeUtente

Password

IDAbilitazioneFK

tblAbilitazione

IDAbilitazionePK

Abilitazione

tblLaboratorio

IDLaboratorioPK

Nome Laboratorio

tblOperazione

Operazione

IDOperazionePK

UsernameFK

Data

IDReagenteDVFK

Locazione passata

tblReagenteDV

IDReagenteDVPKFK

IDStatoFK

Quantità Residua

IDLocazioneFK

tblStato

IDstatoPK

Stato

tblLocazione

IDLocazionePK

Locazione

tblReagenteDF

IDReagenteDFPKFK

IDFornitoreFK

DataAcquisto

IDMisuraFK

UsernameFK

Capacità

DataScadenza

tblUnitàDiMisura

IDMisuraPK

Misura

tblFornitore

Indirizzo

IDFornitorePK

NomeFornitore

Telefono

Fax

Email

Acquirente

Figura 43 : Schema fisico della Gestione Reagenti

Page 55: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

55

UNIONE DELLE GESTIONI E SCHEMA FINALE

Fin’ora per comodità di progettazione e analisi la Gestione Reagenti e la Gestione Sostanza

Chimica sono state analizzate separatamente. In realtà bisogna trovare ora un punto d’incontro,

cioè una relazione che lega le 2 parti in modo tale da poter considerare il tutto come un unico DB.

Partendo dalla progettazione concettuale possiamo trovare un punto d’incontro che per la parte

della Gestione Reagenti può essere l’entità ReagenteDF mentre nella parte della Gestione

Sostanza Chimica possiamo trovare un punto d’incontro nell’entità SostanzaChimica.

REAGENTEDF SOSTANZA CHIMICAReagente-Sostanza

N-1

Figura 44 : Unione a livello concettuale delle 2 entità principali delle Gestione Sostanza Chimica e Reagenti

Ora basta solo considerare tutti gli schemi fin’ora visti come validi ma tenere conto di questa unione.

Basterà inserire una chiave esterna nella tblReagenteDF di nome IDSostanzaChimica e l’unione è completa.

Quindi possiamo osservare prima lo schema E-R finale ristrutturato con attributi, chiavi primarie e esterne.

Page 56: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

56

LEGGENDA:

chiave primaria

chiave esterna

REAGENTE-SOSTANZA

Figura 45 : Schema E-R finale con Gestione Sostanza Chimica e Gestione Reagenti

1-N

Page 57: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

57

Di conseguenza lo schema fisico del DB risulta il seguente

tblSostanzaChimica

NomeSostanza

IDSostanzaChimicaPK

IDClasseFK

CAS

MassaMolecolare

Formula

tblClasse

IDClassePK

ClassetblSinonimo

IDSinonimoPK

IDSostanzaChimicaFK

Sinonimo

IDSinonimoFonteFK

tblFonte

IDFontePK

NomeFonte

urlFonte

tblUtente

NomeUtente

UsernamePK

IDLaboratorioFK

CognomeUtente

Password

IDAbilitazioneFK

tblAbilitazione

IDAbilitazionePK

AbilitazionetblLaboratorio

IDLaboratorioPK

Nome Laboratorio

tblOperazione

Operazione

IDOperazionePK

UsernameFK

Data

IDReagenteDVFK

Locazione passata

tblStato

IDStatoPK

Stato

ReagenteDV

IDReagenteDVPKFK

IDStatoFK

Quantità Residua

IDLocazioneFK

tblLocazione

IDLocazionePK

Locazione

tblUnitàDiMisura

IDMisuraPK

Misura

ReagenteDF

IDReagenteDFPKFK

IDFornitoreFK

Data Scadenza

IDMisuraFK

UsernameFK

IDSostanzaChimicaFK

Data Acquisto

Capacità

tblFornitore

Indirizzo

IDFornitorePK

NomeFornitore

Telefono

Fax

Email

Figura 46 : Schema fisico con Gestione Sostanza Chimica e Gestione Reagenti

Page 58: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

58

SCELTA DEGLI INDICI

Questa fase è di relativa importanza in quanto, SQL Server in generale permette l’indicizzazione

dei vari campi nelle tabelle. Indicizzazione viene fatte per incrementare le prestazioni durante le

varie query sul DB. Ci sono delle norme da seguire per la definizione degli indici che è bene

seguire. Queste sono :

1. Analisi delle operazioni di SELECT più importanti : in questo progetto le operazioni più

comuni, di tipo SELECT che vengono fatte sono quelle di ricerca di un record in una tabella;

2. Analizzare le tabelle con un numero di dati elevati : in questo caso la tabella

tblSostanzaChimica ha un numero di record più elevato rispetto agli altri (circa 5000).

Inoltre è la tabella sulla quale vengono fatte le SELECT più spesso;

3. Analisi delle prestazioni delle varie SELECT sui campi : le operazioni di ricerca fatte con le

SELECT riguardano principalmente il campo CAS della tabella tblSostanzaChimica. L’utente

finale infatti userà quasi sempre il codice CAS per cercare una sostanza chimica in tabella.

Gli altri campi potenziali, quali NomeSostanza e Formula non sono considerati così

fondamentali nella ricerca di una sostanza dall’utente finale, inoltre siccome sono

implicate in altre operazioni (non necessariamente SELECT) la loro indicizzazione

comporterebbe un degrado delle prestazioni;

4. Decisione sul tipo di indice da attivare nel campo selezionato : è stati scelto di usare l’indice

tipo non cluster. Diversamente da un indice cluster un indice non cluster non memorizza

direttamente una parte dei dati in tabella ma memorizza puntatori ai dati corrispondenti

alle colonne in esso definite. Questo tipi di indice viene memorizzato in una struttura

separata rispetto alla tabella. Quando si effettua una ricerca su dati memorizzati su una

tabella sulla quale è definito un indice non cluster SQL Server usa l’informazione definita

nei puntatori dell’indice per individuare le righe che corrispondono ai criteri della ricerca.

Inoltre il tipo di indice qui è stato definito come unique cioè unico. Questo tipo di indice

assicura che i valori contenuti nelle colonne definite nell’indice siano univoci all’interno

della tabella. Infatti il codice CAS è un codice univoco che identifica il record e non può

essere duplicato, per ogni sostanza esiste 1 ed 1 solo;

Tenendo conto di queste osservazioni possiamo concludere che bisogna definire un indice

UNIQUE NON CLUSTER.

Quindi nel DB è stato definito in questo modo :

GO CREATE UNIQUE NONCLUSTERED INDEX [IDX_tblSostanzaChimica] ON [dbo].[tblSostanzaChimica]([CAS] ASC) WHERE ([CAS] IS NOT NULL);

Page 59: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

59

IMPLEMENTAZIONE DELL’INTERFACCIA

L’interfaccia utente (GUI) è di tipo Windows Form. A seconda dei casi descritti, ogni Windows

Form ha 2 o più schede. Ogni scheda ha la sua parte grafica ma il codice è sullo stesso Form. Ciò è

stato utile per semplificare la programmazione. Questo sistema è noto col nome TABCONTROL.

Per maggiori informazioni msdn.microsoft.com.

STRINGA DI CONNESSIONE

Durante la programmazione in Visual Studio, l’IDE crea un file nel quale viene memorizzata la

stringa di connessione al DB. Questo file APP.CONFIG si chiama file di configurazione. Questa

particolarità è fondamentale per il corretto funzionamento.

Il contenuto del file è il seguente :

<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> </configSections> <connectionStrings> <add name="WindowsFormsApplication1.Properties.Settings.ReagentarioConnectionString"

connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Reagentario.mdf;Integrated Security=True;Connect Timeout=30"

providerName="System.Data.SqlClient" /> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration>

La stringa di connessione è la seguente

Le stringhe di connessione possono essere archiviate come coppie chiave/valore nella

sezione connectionStrings dell'elemento configuration di un file di configurazione

dell'applicazione. Gli elementi figlio includono add, clear e remove. L'attributo name corrisponde

al nome specificato per identificare in modo univoco una connessione, in modo che possa essere

recuperato in fase di esecuzione. L'attributo providerName è il nome invariabile del provider di

dati .NET Framework, registrato nel file machine.config. Per maggiori informazioni

msdn.microsoft.com .

Page 60: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

60

OGGETTI DI TIPO SQLCOMMAND

Prima di iniziare a spiegare l’interfaccia come è stata realizzata, iniziamo a spiegare in quale modo

la GUI realizzata comunica con il DB. Questo avviene grazie alla classe SQLCommand. Rappresenta

un'istruzione Transact-SQL o una stored procedure da eseguire in relazione a un database SQL

Server. Questa classe non può essere ereditata. Quindi si capisce che grazie a questa classe le

query vengono scritte direttamente sul codice. Ciò comporta essenzialmente l’introduzione di uno

strato di Middleware che consente all’applicazione di eseguire sul DB tutte le operazioni

pianificate che sono essenzialmente le SELECT,INSERT,UPDATE e DELETE.

DB MIDDLEWARE GUI

Nel successivo paragrafo di spiegazione del codice vengno spiegati in dettaglio tutte le operazioni.

Gli oggetti di tipo SQLComand usati nel progetto vengono inzializzati in questo modo :

1) Si apre connessione col DB;

2) Si crea l’oggetto di tipo SQLComand;

3) Si memorizza la query (che viene vista da codice come una semplice stringa);

4) Si sfrutta il metodo ExecuteNonQuery per eseguire l’istruzione TSQL.

5) Si chiude connessione col DB;

Per maggiori informazioni e ulteriori approfondimenti sul argomento visitare il sito

msdn.microsoft.com

SQL Server

Ogetti

SQLComand:

SELECT,INSERT,UP

DATE,DELETE…

DATAGRIDVIEW

Page 61: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

61

DESCRIZIONE DELL’INTERFACCIA

Form D’ingresso

Partiamo dal Form Principale d’ingresso. Qui possono accedere tutti. Nella Scheda

Rischio\Sicurezza è assicurata la funziona de Ricerca della sostanza chimica in base a 3 criteri di

ricerca : CAS, Nome e Formula. Quindi è stato usato una textbox, un bottone, 3 checkbox per

determinare il criterio di ricerca più adeguato e una datagridview dove vengono presentati i dati.

Basta scorrere la lista con la tastiera o mouse per visualizzare la sostanza, i relativi dati. È stato

aggiunta la possibilità di salvare la lista delle sostanze chimica visualizzata in file Excel grazie ad un

bottone apposito. In Figura vedimao uno screen shot dell’applicazione in uso.

Figura 47 : Scheda Rischio\Sicurezza del Form Iniziale

Page 62: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

62

La ricerca della Sostanza chimica lungo il datagridview è un evento che è reso possibile da

chiunque ed è frequente in questo programma. In seguito viene presentato il relativo codice con

annessa spiegazione.

1. SqlConnection con = new SqlConnection(@"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Reagentario\DB\Reagentario.mdf;Integrated Security=True;Connect Timeout=30;");

a. public bool contaITA = true; b. public bool contaEN = false;

2. public Form1() a. {

i. InitializeComponent(); b. }

3. private void Form2_Load(object sender, EventArgs e) a. {

i. con.Open();

ii. buttonRicerca.Enabled = false; iii. dataGridView1.ClearSelection(); iv. SqlCommand cmd = con.CreateCommand(); v. cmd.CommandType = CommandType.Text; vi. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula FROM tblSostanzaChimica";

vii. cmd.ExecuteNonQuery(); viii. DataTable dt = new DataTable();

ix. SqlDataAdapter da = new SqlDataAdapter(cmd); x. da.Fill(dt); xi. dataGridView1.DataSource = dt;

b. }

La riga n.1 indica la stringa di connessione che in C# và indicata così ed è memorizzata nella

variabile con che è una variabile di tipo SQLConnection. Questa variabile viene aperta nella riga

3.a.i. e poi verrà ovviamente chiusa. La riga n.1.a e 1.b indicano invece 2 variabili booleane che

vengono settati così perché il loro settaggio indica se l’interfaccia deve cambiare la lingua d’uso (

da italiano a inglese e viceversa). La riga n.2 indica l’inizializzazione del Form che è standard. La

riga n.3 invece rappresenta l’evento Caricamento del Form. Dove viene aperta la connessione col

DB con con.Open e dove viene inizializzato il contenuto del primo datagridview, quello che mostra

in griglia i dati della Sostanza Chimica. Nella riga 3.a.ii. invece il bottone buttonRicerca viene

settato a false e viene cambiato in true quando viene selezionato un corretto criterio di ricerca

tramite i checkbox.

Page 63: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

63

1. private void buttonRicerca_Click(object sender, EventArgs e) a. {

2. if (checkBox1.Checked==true && checkBox2.Checked==false && checkBox3.Checked==false) i. { ii. //ricerca per nome iii. SqlCommand cmd = con.CreateCommand(); iv. cmd.CommandType = CommandType.Text; v. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula FROM tblSostanzaChimica WHERE tblSostanzaChimica.NomeSostanza LIKE '%" + textBoxRicFormula.Text + "%'";

vi. cmd.ExecuteNonQuery(); vii. DataTable dt = new DataTable();

viii. SqlDataAdapter da = new SqlDataAdapter(cmd); ix. da.Fill(dt); x. dataGridView1.DataSource = dt; xi. }

3. else if(checkBox1.Checked==false && checkBox2.Checked==true && checkBox3.Checked==false)

i. { ii. //ricerca per CAS iii. SqlCommand cmd = con.CreateCommand(); iv. cmd.CommandType = CommandType.Text; v. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula FROM tblSostanzaChimica WHERE tblSostanzaChimica.CAS LIKE '%" + textBoxRicFormula.Text + "%'";

vi. cmd.ExecuteNonQuery(); vii. DataTable dt = new DataTable();

viii. SqlDataAdapter da = new SqlDataAdapter(cmd); ix. da.Fill(dt); x. dataGridView1.DataSource = dt; xi. }

4. else if(checkBox1.Checked==false && checkBox2.Checked==false && checkBox3.Checked==true)

i. { ii. //ricerca per formula iii. SqlCommand cmd = con.CreateCommand(); iv. cmd.CommandType = CommandType.Text; v. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula FROM tblSostanzaChimica WHERE tblSostanzaChimica.Formula LIKE '%" + textBoxRicFormula.Text + "%'";

vi. cmd.ExecuteNonQuery(); vii. DataTable dt = new DataTable();

viii. SqlDataAdapter da = new SqlDataAdapter(cmd); ix. da.Fill(dt); x. dataGridView1.DataSource = dt; xi. } xii. else MessageBox.Show("Errore criterio di ricerca");

b. }

Questo codice serve pe la Ricerca della Sostanza in base ai criteri di Ricerca selezionati. I criteri di

Ricerca sono rappresentati dai checkbox. L’evento click del bottone buttonRicerca racchiude infatti

4 possibilità :

Ricerca in base al Nome della Sostanza ( riga numero 2 )

Ricerca in base al CAS della Sostanza(riga numero 3)

Page 64: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

64

Ricerca in base alla Formula chimica della Sostanza(riga numero 4)

Errore nel criterio di Ricerca (riga numero 4.x.ii)

Tutte e 3 hanno codice molto simile. Prima si crea l’oggetto SqlComand e poi gli viene dato il testo

della Query SQL che esegue sul DB. Poi la esegue. Adatto il risultato al datagridview.

Un altro evento che si esegue con frequenza e lo scorrere della lista nel datagridview. Questo

evento ha il seguente codice :

1. private void dataGridView1_MouseClick(object sender, MouseEventArgs e) a. {

i. textBoxCAS.Text = dataGridView1.SelectedRows[0].Cells[0].Value.ToString();

ii. textBoxNome.Text = dataGridView1.SelectedRows[0].Cells[1].Value.ToString();

iii. textBoxFormula.Text = dataGridView1.SelectedRows[0].Cells[2].Value.ToString();

iv. button2.Enabled = true;

b. }

2. private void dataGridView1_KeyDown(object sender, KeyEventArgs e) a. {…}

3. private void dataGridView1_KeyUp(object sender, KeyEventArgs e)

a. {…}

Intanto dalla Figura 47 si può notare che per una migliore visualizzazione è stato aggiunto un

GroupBox con varie Label che mostrano il contenuto delle informazioni del datagridview. Questo

viene eseguito nella riga 1,2 o 3. L’evento che provoca tutto ciò è il click sul datagridview col

mouse. La riga 2 e 3 contiene lo stesso codice, soltanto che avviene quando viene premuto il tasto

Freccia Giù\Freccia Sù dalla tastiera.

Page 65: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

65

Figura 48 : Scheda di LogIn

Questa invece è la schermata di LogIn per autenticarsi. Ci sono 2 textbox e un bottone.

L’evento click sul bottone ha il seguente codice C#

1. private void buttonLogIn_Click(object sender, EventArgs e) a. {

2. if (textBoxUsername.Text == "" || textBoxPassword.Text == "") 3. {

i. MessageBox.Show("Non hai inserito Username o Password,riprova"); 4. }

i. //controllo utente se admin o user

5. else { 6. SqlCommand comando = new SqlCommand("SELECT * FROM tblUtente WHERE Username ='" +

textBoxUsername.Text + "' and Password = '" + textBoxPassword.Text + "'and IDAbilitazione= 2", con);

i. SqlDataReader re = comando.ExecuteReader(); ii. bool leggo = re.Read();

7. SqlCommand comando1 = new SqlCommand("SELECT * FROM tblUtente WHERE Username ='" + textBoxUsername.Text + "' and Password = '" + textBoxPassword.Text + "'and IDAbilitazione= 1", con);

i. SqlDataReader re1 = comando1.ExecuteReader(); ii. bool leggo1 = re1.Read();

8. SqlCommand comando2 = new SqlCommand("SELECT * FROM tblUtente WHERE Username ='" + textBoxUsername.Text + "' and Password = '" + textBoxPassword.Text + "'and IDAbilitazione= 3", con);

i. SqlDataReader re2 = comando2.ExecuteReader(); ii. bool leggo2 = re2.Read();

Page 66: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

66

iii. if (leggo && !leggo1 && !leggo2) iv. {

1. //caso user 2. this.Hide(); 3. Form2 f2 = new Form2(); 4. f2.Usr = textBoxUsername.Text; 5. f2.utente = true; 6. f2.ShowDialog();

v. } vi. if (!leggo && leggo1 && !leggo2) vii. {

1. //caso admin 2. this.Hide(); 3. Form2 f2 = new Form2(); 4. f2.Usr = textBoxUsername.Text; 5. f2.utente = false; 6. f2.ShowDialog();

viii. } ix. else { x. if (contaITA == true) xi. {

1. MessageBox.Show("Credenziali sbagliate, Riprova");

xii. } xiii. else xiv. {

1. MessageBox.Show("Credentials are wrong, try again");

xv. } xvi. }

xvii. } b. }

L’evento click del bottone è soggetto ad un controllo che è il seguente : se le textbox sono vuote

allora mostra un messaggio d’errore. Se non sono vuote passa al controllo successivo che è quello

di verificare se l’utente ha un account admin o user. Questo controllo la fanno le righe 6,7 e 8.

Viene definito un oggetto SqlComand comando nel quale scrivo la Query in Sql più gli devo dare

l’oggetto che contiene la stringa di connessione, in questo caso con definito nel evento

caricamento del Fom. Poi definisco un oggetto DataReader che esegue il comando definito prima.

Poi definisco una variabile booleana leggo nella quale memorizzo il risultato di Re.read che tornerà

un valore booleano true se trova il username e password nel DB ,false in caso contrario. Nelle

righe 8.iii e 8.vi viene controllato il valore di queste variabili booleane per capire di quale utente si

tratta. L’ultimo controllo invece è quello relativo alla lingua d’uso. Infatti già qui nel Form d’inizio

possiamo cambiare la lingua d’uso. Questo controllo lo fanno e le variabili booleane contaITA e

contaEN ed avviene nella riga 8.x e 8.xiii.

Inoltre nelle righe 8.iii e 8.vi oltre al controllo di quale utente si tratta, viene caricato il Form2 con

una proprietà che in realtà è una funzione booleana definita all’interno del Form2 che serve per

capire, in base all’utente quali schede caricare nel Form successivo.

Un evento molto frequente è anche il cambio di lingua, che come già anticipato, può avvenire in

qualsiasi momento. Il cambio di lingua è stato progettato come nel menù classico a

Page 67: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

67

tendina(Modifica->Lingua->Italiano;English). Qui c’è anche il bottone per uscire dal

programma(File->Esci) e il bottone ?->Informazioni.

Figura 49 : Form d’Ingresso

Il codice che permette tutto ciò è il seguente :

1. private void esciToolStripMenuItem_Click(object sender, EventArgs e) a. {

i. con.Close(); ii. Environment.Exit(0);

b. }

2. private void englishToolStripMenuItem_Click(object sender, EventArgs e) a. {

i. tabPage1.Text = "Risk Security"; ii. button2.Text = "Open Data Risk-Security"; iii. checkBox1.Text = "Name"; iv. checkBox3.Text = "Chemical formula"; v. groupBox2.Text = "Selected substance"; vi. groupBox1.Text = "Search for "; vii. buttonRicerca.Text = "Search";

viii. label3.Text = "Name"; ix. groupBox3.Text = "Choice between the possible outcomes"; x. modificaToolStripMenuItem.Text = "Modification"; xi. esciToolStripMenuItem.Text = "Exit"; xii. linguaToolStripMenuItem.Text = "Language";

xiii. italianoToolStripMenuItem.Text = "Italian";

Page 68: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

68

xiv. englishToolStripMenuItem.Text = "English"; xv. informazioniToolStripMenuItem.Text = "Information"; xvi. button1.Text = "Save in Excel";

xvii. contaEN = true; xviii. contaITA = false;

b. }

3. private void italianoToolStripMenuItem_Click(object sender, EventArgs e) a. {

i. contaITA = true; ii. contaEN = false; iii. checkBox1.Text = "Nome"; iv. checkBox3.Text = "Formula Chimica"; v. button2.Text = "Apri scheda Rischio-Sicurezza"; vi. tabPage1.Text = "Rischio Sicurezza"; vii. groupBox2.Text = "Sostanza selezionata";

viii. groupBox1.Text = "Ricerca per "; ix. buttonRicerca.Text = "Ricerca"; x. label3.Text = "Nome"; xi. groupBox3.Text = "Scelta tra i possibili risultati"; xii. modificaToolStripMenuItem.Text = "Modifica";

xiii. esciToolStripMenuItem.Text = "Esci"; xiv. linguaToolStripMenuItem.Text = "Lingua"; xv. italianoToolStripMenuItem.Text = "Italiano"; xvi. englishToolStripMenuItem.Text = "Inglese";

xvii. informazioniToolStripMenuItem.Text = "Informazioni"; xviii. button1.Text = "Salva in Excel";

b. }

La riga 1 permette la chiusura del Form e chiusura del programma. La riga n.2 e 3 invece cambiano

i valori delle label , cioè viene fatta la vera e propria traduzione in più vengono settate le variabili

booleane contaITA e contaEN necessarie per gli eventi descritti sopra.

Un’altra particolarità è il salvataggio dei dati presenti nel datagridview1 in un file Excel. Questo

evento avviene cliccando sul bottone Salva su Excel. Il codice che permette di farlo è il seguente :

1. private void button1_Click(object sender, EventArgs e) { i. saveFileDialog1.InitialDirectory = "C"; ii. saveFileDialog1.Title = "Salva su file in Excel"; iii. saveFileDialog1.FileName = ""; iv. saveFileDialog1.Filter = "Excel Files(2003)|*.xls|Excel

Files(2007)|*.xlsx";

2. if (saveFileDialog1.ShowDialog() != DialogResult.Cancel) { i. CopiaExcel copy = new CopiaExcel(); ii. copy.Show(); iii. copy.timer1.Start(); iv. Microsoft.Office.Interop.Excel.Application ExcelApp = new

Microsoft.Office.Interop.Excel.Application(); v. ExcelApp.Application.Workbooks.Add(Type.Missing);

vi. for (int i = 1; i < dataGridView1.Columns.Count + 1; i++) vii. {

1. ExcelApp.Cells[1, i] = dataGridView1.Columns[i - 1].HeaderText;

viii. } ix. for (int i = 0; i < dataGridView1.Rows.Count; i++) x. {

1. for (int j = 0; j < dataGridView1.Columns.Count; j++) 2. {

Page 69: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

69

3. ExcelApp.Cells[i + 2, j + 1] = dataGridView1.Rows[i].Cells[j].Value.ToString();

4. } xi. } xii. ExcelApp.Columns.AutoFit();

xiii. ExcelApp.ActiveWorkbook.SaveCopyAs(saveFileDialog1.FileName.ToString());

xiv. ExcelApp.ActiveWorkbook.Saved = true; xv. ExcelApp.Quit(); xvi. }

b. }

La scrittura fondamentale avviene nella riga 1.a avviene il caricamento della finestra standard di

Salvataggio di un file in Excel, dove viene richiesto il nome del file. La formazione del vero e

proprio file avviene dalla riga 2. Vengono contate le righe e colonne del datagridview (attraverso i

cicli for) e il loro contenuto copiato nel nuovo file. Fintantochè vengono contati i cicli for viene

caricato un altro Form chiamato CopiaExcel , che è una schermata standard di caricamento di un

file, come in figura seguente.

Figura 50 : Salvataggio sul file Excel dei dati presenti in griglia

Page 70: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

70

Le Schede di Rischio\Sicurezza venivano nel programma precedente visualizzate come singole frasi

collegate rispettivamente alla sostanza chimica selezionata. Ora invece , come espressamente

richiesto, le schede di Rischio\Sicurezza sono dei file con estensione PDF nei quali ci sono tutte le

informazioni correlate su quella sostanza. Ogni sostanza ha un file nominato in questo modo :

CAS.PDF. Il CAS è un codice univoco quindi non ci possono essere 2 sostanze con codice CAS

identico, da questo punto di vista è simile ad una chiave primaria. Essendo quindi gestito così, il

bottone “Apri Scheda Rischio\Sicurezza” ha il seguente codice :

1. private void button2_Click(object sender, EventArgs e) a. {

i. string file = "C:\\Reagentario\\CAS-PDF\\" + textBoxCAS.Text + ".pdf"; ii. // iii. if (File.Exists(file)) System.Diagnostics.Process.Start(file); iv. else MessageBox.Show("Attenzione, attualmente non presente");

b. }

Quindi in base alla sostanza chimica che in quel momento è selezionata , premendo sul bottone

appare il file PDF della sostanza chimica corrispondente. Da questo punto in avanti l’utente può ad

esempio stampare tutte le informazioni (con le relative Frasi di Rischio\Sciurezza e molto

altro…)sulla sostanza chimica selezionata.

Scheda Consumo\Spostamento

Figura 51 : Scheda di Consumo

Page 71: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

71

La figura 51 mostra la schermata inziale della scheda di Consumo. L’utente che si è autenticato ha

un account User cioè può fare solo Consumo e\o Spostamento, consultare la Reportistica e

nient’altro.

Il codice per la visualizzazione nella griglia principale è lo stesso, della Scheda R\S vista prima (cioè

si visualizzano tutte le possibili sostanze chimiche presenti nel DB), quello che cambia è la

visualizzazione della griglia sottostante. Qui vengono infatti visualizzati i contenitori e il loro

relativo contenuto, con tutte le informazioni. Il codice che permette ciò è il seguente :

1. public void dataGridView4_MouseClick(object sender, MouseEventArgs e) 2. {

a. textBoxPCAS.Text = dataGridView4.SelectedRows[0].Cells[0].Value.ToString(); b. textBoxPID.Text = Convert.ToString(leggiIDSostanzaChimica(textBoxPCAS.Text)); c. textBoxPNome.Text = dataGridView4.SelectedRows[0].Cells[1].Value.ToString(); d. textBoxPFormula.Text =

dataGridView4.SelectedRows[0].Cells[2].Value.ToString(); i. con.Open(); ii. SqlCommand cmd = con.CreateCommand(); iii. cmd.CommandType = CommandType.Text;

1. cmd.CommandText = "SELECT tblReagenteDF.IDreagente, tblSostanzaChimica.CAS, tblReagenteDF.DataAcquisto, tblReagenteDF.DataScadenza, tblReagenteDF.Capacità, tblReagenteDV.QuantitàResidua, tblReagenteDV.Acquirente, tblLocazione.NomeLocazione, tblUnitàDiMisura.Misura FROM tblReagenteDF INNER JOIN tblSostanzaChimica ON tblSostanzaChimica.IDSostanzaChimica = tblReagenteDF.IDSostanzaChimica INNER JOIN tblReagenteDV ON tblReagenteDF.IDreagente = tblReagenteDV.IDReagente INNER JOIN tblUnitàDiMisura ON tblReagenteDF.IDMisura = tblUnitàDiMisura.IDMisura INNER JOIN tblLocazione ON tblReagenteDV.IDLocazione = tblLocazione.IDLocazione WHERE tblReagenteDF.IDSostanzaChimica ='" + textBoxPID.Text + "'";

iv. cmd.ExecuteNonQuery(); v. con.Close(); vi. DataTable dt = new DataTable(); vii. SqlDataAdapter da = new SqlDataAdapter(cmd);

viii. da.Fill(dt); ix. dataGridView5.DataSource = dt; x. dataGridView5.Columns[0].Visible = false;

1. if (dataGridView5.Rows.Count == 0) 2. { 3. DataTable dt5 = new DataTable(); 4. dataGridView5.DataSource = dt5; 5. buttonPrelievoReagente.Enabled = false; 6. } 7. else {

8. quantità =

dataGridView5.SelectedRows[0].Cells[5].Value.ToString(); 9. quantità1 = Convert.ToDouble(quantità); 10. if (quantità1 > 0) buttonPrelievoReagente.Enabled = true; 11. else buttonPrelievoReagente.Enabled = false; 12. }

xi. f = e; 3. }

4. public void dataGridView4_KeyUp(object sender, KeyEventArgs e) {…}

5. public void dataGridView4_KeyDown(object sender, KeyEventArgs e) {…}

Page 72: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

72

Oltre da notare la Query complessa (2.iii.1), và notato anche il controllo che viene fatto sulla

quantità (righe 2.x1÷2.x.12).Infatti se il reagente selezionato ha quantità pari a zero (cioè boccione

vuoto) allora non si può eseguire nessun consumo, ed il relativo bottone che permette di fare ciò

ha la proprietà Enabled settato a false.

Da notare è la funzione leggiIDSostanzaChimica che dando come parametro d’ingresso una stringa

(il CAS in questo caso) ritorna come valore ID corrispondente al CAS. Il codice è il seguente :

1. public int leggiIDSostanzaChimica(string CAS) a. {

i. int ID = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblSostanzaChimica WHERE

tblSostanzaChimica.CAS = '" + CAS + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) ID = (int)leggi["IDSostanzaChimica"]; vii. con.Close();

viii. return ID;

b. }

Il bottone blu in alto a destra del datagridview invece serve da refresh dei dati. Il codice è :

1. con.Open(); i. SqlCommand cmd = con.CreateCommand(); ii. cmd.CommandType = CommandType.Text; iii. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula FROM tblSostanzaChimica";

iv. cmd.ExecuteNonQuery(); v. DataTable dt = new DataTable(); vi. SqlDataAdapter da = new SqlDataAdapter(cmd); vii. da.Fill(dt);

viii. dataGridView1.DataSource = dt;

2. con.Close(); Viene aperta la connessione con DB, creo un oggetto SqlComand cmd nel quale scrivo la Query in Sql, la adatto e la visualizzo nel datagridview corrispondente. Il codice evento del bottone PrelievoReagente è il seguente :

1. private void buttonPrelievoReagente_Click(object sender, EventArgs e) a. {

i. Form3 f3 = new Form3(); ii. f3.portoID = leggiIDSostanzaChimica(textBoxPCAS.Text); iii. f3.portoCAS = textBoxPCAS.Text; iv. f3.portoNome = textBoxPNome.Text; v. f3.portoMassa = textBoxPMassa.Text; vi. f3.portoFormula = textBoxPFormula.Text; vii. f3.portoIDR = dataGridView5.SelectedRows[0].Cells[0].Value.ToString();

viii. f3.portoCap = dataGridView5.SelectedRows[0].Cells[4].Value.ToString(); ix. f3.portoQuantitàR =

dataGridView5.SelectedRows[0].Cells[5].Value.ToString(); x. f3.portoLocazione =

dataGridView5.SelectedRows[0].Cells[7].Value.ToString();

Page 73: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

73

xi. f3.portoDataAcquisto = dataGridView5.SelectedRows[0].Cells[2].Value.ToString();

xii. f3.portoDataScadenza = dataGridView5.SelectedRows[0].Cells[3].Value.ToString();

xiii. f3.portoUnità = dataGridView5.SelectedRows[0].Cells[8].Value.ToString();

xiv. f3.Acquirente = dataGridView5.SelectedRows[0].Cells[6].Value.ToString();

xv. f3.portoUsr = provUsr; xvi. f3.criga =

dataGridView4.Rows.GetFirstRow(DataGridViewElementStates.Selected); xvii. f3.f2 = this; xviii. f3.Show();

b. }

Questo codice è legato alle funzioni che sono state scritte appositamente nel Form3(quello del

Consumo). Ogni volta che si preme il bottone e che si apre il Form3 le informazioni vengono

spedite al Form del consumo grazie alle seguenti funzioni :

private string tempCAS = string.Empty; private string tempNome = string.Empty; private string tempFormula = string.Empty; private string tempIDR = string.Empty; private string tempCap = string.Empty; private string tempQuantitàR = string.Empty; private string tempLocazione = string.Empty; private string tempDataAcquisto = string.Empty; private string tempDataScadenza = string.Empty; private string tempQuantitàP = string.Empty; private string tempUnità = string.Empty; private string tempUsr = string.Empty; private string Acq = string.Empty; private int riga = 0; private int tempID = 0;

public int criga { get { return riga; } set { riga = value; } } public int portoID { get { return tempID; } set{tempID = value;} } public string portoCAS { get { return tempCAS; } set { tempCAS = value; } } public string portoNome { get { return tempNome; } set { tempNome = value; } } public string portoFormula { get { return tempFormula; } set { tempFormula = value; } } public string portoIDR {

Page 74: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

74

get { return tempIDR; } set { tempIDR = value; } } public string portoCap { get { return tempCap; } set { tempCap = value; } } public string portoQuantitàR { get { return tempQuantitàR; } set { tempQuantitàR = value; } } public string portoLocazione { get { return tempLocazione; } set { tempLocazione = value; } } public string portoDataAcquisto { get { return tempDataAcquisto; } set { tempDataAcquisto = value; } } public string portoDataScadenza { get { return tempDataScadenza; } set { tempDataScadenza = value; } } public string portoQuantitàP { get { return tempQuantitàP; } set { tempQuantitàP = value; } } public string portoUnità { get { return tempUnità; } set { tempUnità = value; } } public string portoUsr { get { return tempUsr; } set { tempUsr = value; } } public string Acquirente { get { return Acq; } set { Acq = value; } }

Una volta che si preme il bottone del prelievo compare la seguente schermata :

Page 75: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

75

Figura 52 : Form Consumo Reagente

Questo Form esegue il consumo vero e proprio. Intanto tutte le label che non si possono

modificare prendono le informazioni dal Form precedente, più precisamente dai datagridview

selezionati.

Le informazioni variabili, cioè quelle che l’utente può modificare è la Quantità prelevata. Come si

vede è stata introdotta la possibilità di consumo totale della quantità e del consumo parziale. Per i

numeri decimali è stato usato il punto “.” come separatore.

Il codice che permette di avere solo numeri decimali col punto “.” come separatore è il seguente :

i. private void textBoxQuantitàpre_KeyPress(object sender, KeyPressEventArgs e) a. {

i. char ch = e.KeyChar;

ii. if (ch == 46 && textBoxQuantitàpre.Text.IndexOf('.') != -1) { iii. e.Handled = true; iv. return; v. } vi. if(!Char.IsDigit(ch) && ch!= 8 && ch!=46){ vii. e.Handled = true;

viii. }

b. }

In pratica questo codice permette di inserire solo i numeri da tastiera(se si premono i tasti delle

lettere non li visualizza), anche numeri decimali ma col punto come separatore (se si preme la

virgola non la visualizza come gli altri caratteri che non siano numeri).

Page 76: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

76

A parte il Bottone Annulla di funzionamento ovvio, chi desta senz’latro interesse è il bottone

Registra. Il codice che ne descrive il funzionamento è il seguente :

1. private void buttonReg_Click(object sender, EventArgs e) a. {

i. int IDR = Int32.Parse(textBoxIDR.Text); ii. string Usr = tempUsr; iii. double ris;

iv. double IDRF = Convert.ToDouble(textBoxQuantitàR.Text);//quantità

residua v. if (textBoxQuantitàpre.Enabled == true && ( textBoxQuantitàpre.Text ==

"" || textBoxQuantitàpre.Text == "0")) MessageBox.Show("Errore nella quantità prelevata,ricontrolla");

vi. else vii. {

viii. if (checkBox1.Checked == true && checkBox2.Checked == false) ix. {//prelevo tutto

1. SqlCommand update = new SqlCommand(); 2. update.CommandType = CommandType.Text; 3. update.CommandText = "UPDATE tblReagenteDV SET

[QuantitàResidua]=@QR, [IDStato]=@IDS WHERE IDReagente = '" + textBoxIDR.Text + "'";

4. //update.Parameters.AddWithValue("@QuantitàResidua", somma); 5. update.Parameters.AddWithValue("@QR", 0); 6. update.Parameters.AddWithValue("@IDS", 3); 7. update.Connection = con; 8. con.Open(); 9. update.ExecuteNonQuery(); 10. con.Close();

x. } xi. else if (checkBox1.Checked == false && checkBox2.Checked == true) xii. {

1. NumberFormatInfo provider = new NumberFormatInfo(); 2. provider.NumberDecimalSeparator = "."; 3. ris = Convert.ToDouble(textBoxQuantitàpre.Text,

provider);//quantità prelevata col punto dalla textbox 4. if (ris > IDRF) MessageBox.Show("Non puoi prelevare più di

quanto c'è, controlla la quantità prelevata"); 5. else

a. { b. double nd1 = Math.Round(IDRF - ris, 2); c. SqlCommand update = new SqlCommand(); d. update.CommandType = CommandType.Text; e. update.CommandText = "UPDATE tblReagenteDV SET

[QuantitàResidua]=@QR, [IDStato]=@IDS WHERE IDReagente = '" + textBoxIDR.Text + "'";

f. update.Parameters.AddWithValue("@QR", nd1); g. update.Parameters.AddWithValue("@IDS", 1); h. update.Connection = con; i. con.Open(); j. update.ExecuteNonQuery(); k. con.Close();

l. }

6. }

7. f2.dataGridView4.Rows[riga].Selected = true; 8. f2.dataGridView4_MouseClick(f2.dataGridView4, f2.f); 9. //aggiorna la tblOperazione

Page 77: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

77

10. AggiornaOp(); 11. DataTable dt = new DataTable(); 12. f2.dataGridView6.ClearSelection(); 13. f2.dataGridView7.DataSource = dt; 14. f2.dataGridView8.ClearSelection(); 15. f2.dataGridView9.DataSource = dt; 16. f2.buttonDatiReso.Enabled = false; 17. f2.bottoni();

xiii. MessageBox.Show("Consumo registrato con successo"); xiv. Close(); xv. }

b. }

2. private void AggiornaOp() {

i. string query = "INSERT INTO tblOperazione (Operazione, Username, Data, Locazionepassata, IDreagente) VALUES (@Op, @User, @Data, @Locpas, @IDR)";

ii. SqlCommand insert = new SqlCommand(query, con); iii. insert.Parameters.AddWithValue("@Op", "Consumo"); iv. insert.Parameters.AddWithValue("@User", tempUsr); v. insert.Parameters.AddWithValue("@Data", DateTime.Now.Date); vi. insert.Parameters.AddWithValue("@Locpas", DBNull.Value); vii. insert.Parameters.AddWithValue("@IDR", tempIDR);

viii. con.Open(); ix. insert.ExecuteNonQuery(); x. con.Close();

b. }

Come prima cosa vengono inizializzate le variabili. Ci sono 2 checkbox, 1 che indica il prelievo

totale e una che indica il prelievo parziale. Nel caso di prelievo totale (1.a.viii÷1.a.x) la quantità

residua viene posto a 0, e lo stato del reagente viene posto a 3 (che rappresenta a chiave primaria

dello stato “Esaurito”). Quando invece eseguiamo un prelievo parziale (cioè diamo un input da

tastiera sulla quantità da prelevare) allora per prima cosa alla riga 1.a.v viene eseguito un test (per

non inserire quantità che non hanno senso come il campi vuoto oppure 0) e poi dalla riga 1.a.xi

viene eseguito il prelievo parziale. Nel caso si inserisca una quantità maggiore di quella disponibile

compare un messaggio d’errore. Poi nelle righe successive viene fatto il calcolo di quello che

rimane nel boccione una volta prelevata la quantità (riga 1.a.xii.4), e poi viene aggiornata la

quantità nella tabella del reagente, e viene settato a 1 lo stato del reagente che vuol dire

“Disponibile” (questa particolarità si poteva anche omettere in quanto la sostanza se viene

eseguito un prelievo parziale rimane comunque ancora disponibile).

Fatto questo le righe successive 1.a.xii.7÷1.a.xii.17 servono per fare un reset di tutte le griglie che

si trovano nel form principale. Ciò è importante per veder in modo automatico i cambiamenti

effettuati dopo un consumo.

Nella riga n.2 invece viene eseguita una procedura che è standard in questo programma. Dopo

ogni consumo o prelievo o modifica o inserimento di un reagente questa procedura viene eseguita

in quanto è quella che scrive nella tabella tblOperazione i dati necessari per la Reportistica. I dati

fondamentali sono :

Il tipo di Operazione (in questo caso consumo)

Page 78: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

78

L’utente che esegue questa operazione (la sua chiave primaria Username)

La data di esecuzione dell’operazione

Una locazione passata (campo non obligatorio in questo caso ma fondamentale nel

operazione di spostamento)

La chiave primaria del reagente coinvolto

Il form relativo allo Spostamento invece compare così:

Figura 53 : Scheda di Spostamento

Questa schermata server per lo Spostamento della sostanza. In questa scheda la locazione

l’informazione fondamentale è la locazione. Il codice per la visualizzazione è lo stesso del form

Consumo. L’unica cosa sono le informazioni quelle che cambiano. Nella griglia sottostante a quella

principale le informazioni che compaiono sono infatti il CAS, la capacità del boccione, la quantità

residua, la misura, la locazione corrente e nome e cognome del utente che lo ha inserito.

Il bottone Sposta Reagente Selezionato invece apre il Form come in figura :

Page 79: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

79

Figura 54 : Form Spostamento

Tutti i dati presenti nelle varie label a sinistra sono non modificabili dall’utente, in quanto presi dal

Form precedente, col meccanismo delle funzioni, già enunciato prima. L’unico dato modificabile è

la Nuova Destinazione. Qui abbiamo una combobox dove si seleziona la nuova locazione. Questa

combobox viene caricata con i dati presenti nella tblLocazione. Il codice di carimento della

combobox è il seguente (codice tratto dalla procedura di Load del Form) :

i. con.Open(); ii. SqlDataReader leggi = null; iii. SqlCommand cmd = new SqlCommand("SELECT * FROM tblLocazione", con); iv. leggi = cmd.ExecuteReader(); v. while (leggi.Read()) comboBoxDest.Items.Add(leggi["NomeLocazione"]); vi. comboBoxDest.SelectedText = textBoxLocazioneARR.Text; vii. con.Close();

Il bottone Registra all’inizio è settato a false. Infatti c’è un codice di controllo sulla combobox. Se

infatti si cambia la locazione allora il bottone viene settato a true, altrimenti rimane a false. Il

codice che permette di fare ciò è il seguente :

1. private void comboBoxDest_SelectedIndexChanged(object sender, EventArgs e) a. {

i. buttonRR.Enabled = true;

b. }

Il bottone Registra invece ha il seguente codice :

Page 80: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

80

1. private void buttonRR_Click(object sender, EventArgs e) 2. {

i. SqlCommand update = new SqlCommand(); ii. update.CommandType = CommandType.Text; iii. update.CommandText = "UPDATE tblReagenteDV SET [IDLocazione]=@IDLoc

WHERE IDReagente = '" + tempID + "'";

iv. update.Parameters.AddWithValue("@IDLoc", Locazione(comboBoxDest.Text)); v. update.Connection = con; vi. con.Open(); vii. update.ExecuteNonQuery();

viii. con.Close(); ix. MessageBox.Show("Locazione cambiata con successo"); x. //aggiornare la tblOperazione xi. AggiornaOp(); xii. f2.dataGridView6.Rows[riga].Selected = true;

xiii. f2.dataGridView6_MouseClick(f2.dataGridView6, f2.k); xiv. DataTable dt = new DataTable(); xv. f2.dataGridView8.ClearSelection(); xvi. f2.dataGridView9.DataSource = dt;

xvii. f2.dataGridView4.ClearSelection(); xviii. f2.dataGridView5.DataSource = dt;

xix. f2.buttonPrelievoReagente.Enabled = false; xx. f2.bottoni(); xxi. //f2.buttonDatiReso.Enabled = false;

xxii. Close(); 3. }

4. private int Locazione(string Loc) { 5. con.Open(); 6. int ID = 0; 7. SqlDataReader leggi = null; 8. SqlCommand cmd = new SqlCommand("SELECT * FROM tblLocazione WHERE

tblLocazione.NomeLocazione = '" + Loc + "'", con); 9. leggi = cmd.ExecuteReader(); 10. while (leggi.Read()) ID = (int)leggi["IDLocazione"]; 11. con.Close(); 12. return ID;

13. }

Questo codice esegue lo Spostamento. Lo spostamento però, per il DB, non è nient’altro che un

update della tabella tblLocazione. Nella variabile tempID c’è l’ID del reagente coninvolto. Viene

cambiata l’ID della tblLocazione che è chiave esterna. Per fare questo viene chiamata una funzione

Locazione che data una stringa come parametro d’ingresso (la stringa che compare nella

combobox ) restituisce la relativa chiave primaria della tabella tblLocazione (riga 2.iv).

L’ultima scheda è quella di LogOut che è quella dove ci riporta al Form d’Inizio.

Page 81: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

81

Figura 55 : Scheda di LogOut

Scheda di Gestione reagenti

La scheda Gestione reagenti è raggiugibile soltanto da un utente di tipo administrator. Si presenta

così :

Page 82: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

82

Figura 56 : Scheda Gestione reagenti

Da notare è la griglia inferiore. Qui infatti vengono visualizzati tutti i reagenti di quella particolare

sostanza chimica. Il codice che ne permette la visualizzazione è il seguente :

1. public void dataGridView8_MouseClick(object sender, MouseEventArgs e) a. {

i. textBox4.Text = dataGridView8.SelectedRows[0].Cells[0].Value.ToString();

ii. textBox5.Text = Convert.ToString(leggiIDSostanzaChimica(textBox4.Text));

iii. textBox3.Text = dataGridView8.SelectedRows[0].Cells[1].Value.ToString();

iv. textBox1.Text = dataGridView8.SelectedRows[0].Cells[2].Value.ToString();

v. button4.Enabled = true; vi. con.Open(); vii. SqlCommand cmd = con.CreateCommand();

viii. cmd.CommandType = CommandType.Text; ix. cmd.CommandText = "SELECT tblReagenteDF.IDreagente,

tblSostanzaChimica.CAS, tblSostanzaChimica.NomeSostanza, tblReagenteDF.Progressivo, tblStato.Stato, tblReagenteDV.QuantitàResidua, tblReagenteDV.Acquirente, tblReagenteDF.Capacità, tblUnitàDiMisura.Misura, tblLocazione.NomeLocazione, tblReagenteDF.DataAcquisto, tblReagenteDF.DataScadenza, tblFornitore.NomeFornitore, tblUtente.CognomeUtente,tblUtente.NomeUtente, tblReagenteDF.Username FROM tblReagenteDF INNER JOIN tblReagenteDV ON tblReagenteDF.IDreagente = tblReagenteDV.IDReagente INNER JOIN tblSostanzaChimica ON tblReagenteDF.IDSostanzaChimica = tblSostanzaChimica.IDSostanzaChimica INNER JOIN tblLocazione ON tblReagenteDV.IDLocazione =

Page 83: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

83

tblLocazione.IDLocazione INNER JOIN tblUnitàDiMisura ON tblReagenteDF.IDMisura = tblUnitàDiMisura.IDMisura INNER JOIN tblFornitore ON tblReagenteDF.IDFornitore = tblFornitore.IDFornitore INNER JOIN tblUtente ON tblReagenteDF.Username = tblUtente.Username INNER JOIN tblStato ON tblReagenteDV.IDStato = tblStato.IDStato WHERE tblReagenteDF.IDSostanzaChimica = '" + textBox5.Text + "'";

x. cmd.ExecuteNonQuery(); xi. con.Close(); xii. DataTable dt = new DataTable();

xiii. SqlDataAdapter da = new SqlDataAdapter(cmd); xiv. da.Fill(dt); xv. dataGridView9.DataSource = dt; xvi. dataGridView9.Columns[0].Visible = false;

xvii. if (dataGridView9.Rows.Count == 0) button2.Enabled = button3.Enabled =

button5.Enabled = false; xviii. else button2.Enabled = button3.Enabled = button5.Enabled = true;

xix. g = e;

b. } 2. private void dataGridView8_KeyDown(object sender, KeyEventArgs e) {…}

3. private void dataGridView8_KeyUp(object sender, KeyEventArgs e) 4. {…}

Di interesse sono i bottoni sottostanti. In particolare i bottoni Aggiungi,Modifica ed Elimina.

Il bottone Modifica ape il seguente Form :

Figura 57 : Form Modifica Reagente

Page 84: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

84

Qui in questo form vengono riportati i dati del reagente selezionato nel form precedente. Per

trasportare i dati si usa come sempre il meccanismo setter-getter. Si possono cambiare la Data

Acquisto, Capacità, Unità di Misura, Fornitore, Locazione, Disponibilità (Username compare ma è

non modificabile). Fornitore e Locazione sono combobox. Il codice del bottone Modifica è il

seguente :

1. private void button2_Click(object sender, EventArgs e) a. {

i. NumberFormatInfo provider1 = new NumberFormatInfo(); ii. provider1.NumberDecimalSeparator = "."; iii. double C = Double.Parse(textBox8.Text,provider1);//disponibilità iv. double C1 = Double.Parse (textBox4.Text,provider1);//capacità v. double C2; vi. if (textBox3.Text == "") C2 = 0; vii. else C2 = Double.Parse(textBox3.Text,provider1);

viii. if (textBox2.Text == "" || textBox2.Text == "0" || textBox4.Text == "" || textBox8.Text == "" || comboBox1.Text == "" || comboBox2.Text == "" || comboBox4.Text == "") MessageBox.Show("Errore, hai lasciato campi vuoti");

ix. else if (C+C2 > C1) MessageBox.Show("Errore controlla le quantità"); x. else

1. { xi. updateReagenteDV(); xii. updateReagenteDF();

xiii. AggiornaOp(); xiv. MessageBox.Show("Dati aggiornati con successo"); xv. f2.dataGridView8.Rows[riga].Selected = true; xvi. f2.dataGridView8_MouseClick(f2.dataGridView8, f2.g);

xvii. DataTable dt = new DataTable(); xviii. f2.dataGridView6.ClearSelection();

xix. f2.dataGridView7.DataSource = dt;

xx. f2.dataGridView4.ClearSelection(); xxi. f2.dataGridView5.DataSource = dt;

xxii. f2.buttonPrelievoReagente.Enabled = false; xxiii. f2.buttonDatiReso.Enabled = false; xxiv. Close();

1. } b. }

2. private void AggiornaOp() {…}

3. private void updateReagenteDV() {

i. NumberFormatInfo provider = new NumberFormatInfo(); ii. provider.NumberDecimalSeparator = "."; iii. double QR = Convert.ToDouble(textBox8.Text, provider); iv. SqlCommand update = new SqlCommand(); v. update.CommandType = CommandType.Text; vi. update.CommandText = "UPDATE tblReagenteDV SET [IDStato]=@IDS,

[QuantitàResidua]= @QuantitàResidua, [IDLocazione]=@IDLocazione, [Acquirente]= @Acq WHERE IDReagente = '" + textBox1.Text + "'";

1. if (QR > 0) update.Parameters.AddWithValue("@IDS", 1); 2. else update.Parameters.AddWithValue("@IDS", 2); 3. if (checkBox1.Checked == true) {

a. double QR1 = Convert.ToDouble(textBox3.Text, provider); b. double tot = Math.Round(QR + QR1, 2); c. update.Parameters.AddWithValue("@QuantitàResidua", tot); d. }

4. else update.Parameters.AddWithValue("@QuantitàResidua", QR);

Page 85: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

85

5. update.Parameters.AddWithValue("@IDLocazione", leggiIDLocazione(comboBox2.Text));

6. update.Parameters.AddWithValue("@Acq", textBox2.Text); 7. update.Connection = con; 8. con.Open(); 9. update.ExecuteNonQuery(); 10. con.Close();

i. } 4. private int leggiIDLocazione(string Locazione) {

i. int IDL=0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblLocazione WHERE

tblLocazione.NomeLocazione = '"+Locazione+"'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDL = (int)leggi["IDLocazione"]; vii. con.Close();

viii. return IDL; a. }

5. private void updateReagenteDF() {

i. NumberFormatInfo provider = new NumberFormatInfo(); ii. provider.NumberDecimalSeparator = "."; iii. double QR = Convert.ToDouble(textBox4.Text, provider); iv. DateTime data1 = dateTimePicker1.Value; v. SqlCommand update1 = new SqlCommand(); vi. update1.CommandType = CommandType.Text; vii. update1.CommandText = "UPDATE tblReagenteDF SET [DataAcquisto]= @DA,

[Capacità]= @Cap, [Username]=@User, [IDFornitore]=@IDF, [IDMisura]=@IDMisura, [Progressivo]=@Prog WHERE IDreagente = '" + textBox1.Text + "'";

viii. update1.Parameters.AddWithValue("@DA", data1); ix. update1.Parameters.AddWithValue("@Cap", QR); x. update1.Parameters.AddWithValue("@User", Username); xi. update1.Parameters.AddWithValue("@IDF",

leggiIDFornitore(comboBox1.Text)); xii. update1.Parameters.AddWithValue("@IDMisura",leggiIDMisura(comboBox4.Tex

t) ); xiii. update1.Parameters.AddWithValue("@Prog", textBox5.Text); xiv. update1.Connection = con; xv. con.Open(); xvi. update1.ExecuteNonQuery();

xvii. con.Close(); i. }

6. private int leggiIDFornitore(string Fornitore) {

i. int IDF = 0; ii. con.Open(); iii. SqlDataReader leggi1 = null; iv. SqlCommand cmd1 = new SqlCommand("SELECT * FROM tblFornitore WHERE

tblFornitore.NomeFornitore = '" + Fornitore + "'", con); v. leggi1 = cmd1.ExecuteReader(); vi. while (leggi1.Read()) IDF = (int)leggi1["IDFornitore"]; vii. con.Close();

viii. return IDF; b. }

7. private int leggiIDMisura (string Misura){

i. int IDM=0; ii. con.Open(); iii. SqlDataReader leggi2 = null; iv. SqlCommand cmd2 = new SqlCommand("SELECT * FROM tblUnitàDiMisura WHERE

tblUnitàDiMisura.Misura = '" + Misura + "'", con);

Page 86: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

86

v. leggi2 = cmd2.ExecuteReader(); vi. while (leggi2.Read()) IDM = (int)leggi2["IDMisura"]; vii. con.Close();

viii. return IDM; ix. }

Vediamo dal codice che bisogna agire su due tabelle per fare le modifiche richieste ossia

tblReagenteDF e tblReagenteDV. E infatti sono state create 2 procedure updateReagenteDF e

updateReagenteDV che eseguono l’update dei dati del reagente.

La procedura private int leggiIDLocazione(string Locazione) dà come risultato la chiave

primaria (un intero) , dando come parametro d’ingresso una stringa chiamata locazione che non è

altro che la stringa di testo selezionata nella combobox. Grazie alla stringa locazione, trova il

valore corrispondente della chiave primaria e la usa per modificare quella esterna nella

tblReagenteDV. Tutta la procedura private void updateReagenteDV() della riga n.3 è simile a tutte

le update descritte fin’ora.

Lo stesso discorso vale per la procedura private void updateReagenteDF() della riga n.5. Avendo

però qui due chiavi esterne serviranno 2 nuove procedure che come nel caso precedente hanno

dei parametri d’ingresso, grazie ad essi trovano nelle rispettive tabelle le chiavi primarie associate

a quei record e poi modificano la chiave esterna nella propria tabella(riga n.6 e 7).

Per il Fornitore c’è la possibilità di inserire immediatamente un nuovo Fornitore. Si apre il

seguente Form

Figura 58 : Scheda Nuovo Fornitore

Page 87: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

87

Qui un l’administrator può inserire i dati del nuovo Fornitore e memorizzarli. Il codice del bottone

Registra è il seguente :

1. private void button1_Click(object sender, EventArgs e) a. {

i. if (textBox1.Text == "" || textBox2.Text == "") MessageBox.Show("Nome Fornitore e Indirizzo sono campi obbligatori");

ii. else { iii. string query = "INSERT INTO tblFornitore (NomeFornitore, Indirizzo,

Telefono, Fax, Email ) VALUES (@NF, @Ind, @Tel, @Fax, @Email)"; iv. SqlCommand insert = new SqlCommand(query, con); v. insert.Parameters.AddWithValue("@NF", textBox1.Text); vi. insert.Parameters.AddWithValue("@Ind", textBox2.Text); vii. insert.Parameters.AddWithValue("@Tel", textBox3.Text);

viii. insert.Parameters.AddWithValue("@Fax", textBox4.Text); ix. insert.Parameters.AddWithValue("@Email", textBox5.Text); x. con.Open(); xi. insert.ExecuteNonQuery(); xii. con.Close();

xiii. MessageBox.Show("Dati fornitore inseriti con successo"); xiv. Close(); xv. }

b. }

I campi Fornitore e Indirizzo sono campi obbligatori (riga 1.a.i). La procedura d’inserimento è

quella standard.

Ora vediamo il bottone Aggiungi sempre nella Scheda Gestione Reagenti. Il Form che si apre è il

seguente :

Figura 59 : Form Inserisci Reagente

Page 88: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

88

I Campi della date sono Oggetti DateTimePicker. Data scadenza ed eliminazione non sono dati

necessari. I restanti sono tutti campi da popolare. Il bottone Registra ha il seguente codice :

1. private void button1_Click(object sender, EventArgs e) {

2. if (textBox1.Text == "" || textBox1.Text == "0" || textBox2.Text == "" || textBox3.Text == "" || comboBox1.Text == "" || comboBox2.Text == "" || comboBox4.Text == "") MessageBox.Show("Errore,ci sono campi vuoti, ricontrolla");

3. else { i. if (checkBox3.Checked == false) ii. {//inserimento singolo

1. inserisciReagenteDF(); 2. inserisciReagenteDV(); 3. AggiornaOp(); 4. MessageBox.Show("Nuovo reagente inserito con successo");

iii. } iv. else if (checkBox3.Checked == true){

1. //inserimento multiplo 2. int n = Int32.Parse( textBox5.Text); 3. for (int i = 0; i < n; i++) { 4. inserisciReagenteDF(); 5. inserisciReagenteDV(); 6. AggiornaOp(); 7. } 8. MessageBox.Show("Nuovi reagenti inseriti con successo");

v. } vi. f2.dataGridView8.Rows[riga].Selected = true; vii. f2.dataGridView8_MouseClick(f2.dataGridView8, f2.g);

viii. DataTable dt = new DataTable(); ix. f2.dataGridView6.ClearSelection(); x. f2.dataGridView7.DataSource = dt; xi. f2.dataGridView4.ClearSelection(); xii. f2.dataGridView5.DataSource = dt;

xiii. f2.buttonPrelievoReagente.Enabled = false; xiv. f2.buttonDatiReso.Enabled = false; xv. Close(); xvi. }

b. }

4. private void AggiornaOp() {…}

5. private void inserisciReagenteDF() {

i. DateTime dt1= dateTimePicker1.Value;//data acquisto ii. DateTime dt2 = dateTimePicker2.Value;//data scadenza iii. DateTime dt3 = dateTimePicker3.Value;//data eliminazione iv. NumberFormatInfo provider = new NumberFormatInfo(); v. provider.NumberDecimalSeparator = "."; vi. double cap = Convert.ToDouble(textBox1.Text, provider); vii. //mi serve l'IDFornitore

viii. if (checkBox1.Checked == false && checkBox2.Checked == true) {//ho la data scadenza ma non la eliminazione

ix. string query = "INSERT INTO tblReagenteDF (IDSostanzaChimica, DataAcquisto, DataScadenza, Capacità, IDFornitore, Username, IDMisura ) VALUES (@IDS, @DA, @DS, @Cap, @IDF, @Usr, @IDM)";

x. SqlCommand insert = new SqlCommand(query, con); xi. insert.Parameters.AddWithValue("@IDS", IDS); xii. insert.Parameters.AddWithValue("@DA", dt1);

xiii. insert.Parameters.AddWithValue("@DS", dt2); xiv. insert.Parameters.AddWithValue("@Cap", cap); xv. insert.Parameters.AddWithValue("@IDF", IDFornitore(comboBox1.Text)); xvi. insert.Parameters.AddWithValue("@Usr", textBox4.Text);

Page 89: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

89

xvii. insert.Parameters.AddWithValue("@IDM", IDMisura(comboBox4.Text)); xviii. con.Open();

xix. insert.ExecuteNonQuery(); xx. con.Close(); xxi. }

xxii. else if (checkBox1.Checked == true && checkBox2.Checked == false) xxiii. {//ho la data di eliminazione ma non la scadenza xxiv. string query = "INSERT INTO tblReagenteDF (IDSostanzaChimica,

DataAcquisto, DataEliminazione, Capacità, IDFornitore, Username, IDMisura ) VALUES (@IDS, @DA, @DE, @Cap, @IDF, @Usr, @IDM)";

xxv. SqlCommand insert = new SqlCommand(query, con); xxvi. insert.Parameters.AddWithValue("@IDS", IDS); xxvii. insert.Parameters.AddWithValue("@DA", dt1); xxviii. insert.Parameters.AddWithValue("@DE", dt3); xxix. insert.Parameters.AddWithValue("@Cap", cap); xxx. insert.Parameters.AddWithValue("@IDF", IDFornitore(comboBox1.Text));

xxxi. insert.Parameters.AddWithValue("@Usr", textBox4.Text); xxxii. insert.Parameters.AddWithValue("@IDM", IDMisura(comboBox4.Text)); xxxiii. con.Open(); xxxiv. insert.ExecuteNonQuery(); xxxv. con.Close(); xxxvi. } xxxvii. else { // nè data scadenza nè eliminazione

1. string query = "INSERT INTO tblReagenteDF (IDSostanzaChimica, DataAcquisto, Capacità, IDFornitore, Username, IDMisura ) VALUES (@IDS, @DA, @Cap, @IDF, @Usr, @IDM)";

2. SqlCommand insert = new SqlCommand(query, con); 3. insert.Parameters.AddWithValue("@IDS", IDS); 4. insert.Parameters.AddWithValue("@DA", dt1); 5. insert.Parameters.AddWithValue("@Cap", cap); 6. insert.Parameters.AddWithValue("@IDF",

IDFornitore(comboBox1.Text)); 7. insert.Parameters.AddWithValue("@Usr", textBox4.Text); 8. insert.Parameters.AddWithValue("@IDM",

IDMisura(comboBox4.Text)); 9. con.Open(); 10. insert.ExecuteNonQuery(); 11. con.Close();

xxxviii. } b. }

6. private void inserisciReagenteDV() { i. NumberFormatInfo provider = new NumberFormatInfo(); ii. provider.NumberDecimalSeparator = "."; iii. int stato = 1; iv. double QR = Convert.ToDouble(textBox2.Text, provider); v. string query = "INSERT INTO tblReagenteDV (IDReagente, IDStato,

QuantitàResidua, IDLocazione, Acquirente) VALUES (@IDR, @IDStato, @QR, @IDL, @Acq)";

vi. SqlCommand insert1 = new SqlCommand(query, con); vii. insert1.Parameters.AddWithValue("@IDR",leggiIDReagenteDF());

viii. insert1.Parameters.AddWithValue("@IDStato", stato); ix. insert1.Parameters.AddWithValue("@QR", QR); x. insert1.Parameters.AddWithValue("@IDL", IDLocazione(comboBox2.Text)); xi. insert1.Parameters.AddWithValue("@Acq", textBox3.Text); xii. con.Open();

xiii. insert1.ExecuteNonQuery(); xiv. con.Close();

b. }

7. private int leggiIDReagenteDF() { i. int IDR = 0; ii. con.Open(); iii. SqlDataReader leggi = null;

Page 90: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

90

iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblReagenteDF WHERE tblReagenteDF.IDSostanzaChimica = '" + IDS + "'", con);

v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDR = (int)leggi["IDreagente"]; vii. con.Close();

viii. return IDR; b. }

8. private int IDLocazione(string Locazione) {

i. int ITL = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblLocazione WHERE

tblLocazione.NomeLocazione = '" + Locazione + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) ITL = (int)leggi["IDLocazione"]; vii. con.Close();

viii. return ITL; b. }

9. private int IDFornitore(string Fornitore) { i. int IDF = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblFornitore WHERE

tblFornitore.NomeFornitore = '" + Fornitore + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDF = (int)leggi["IDFornitore"]; vii. con.Close();

viii. return IDF; b. }

10. private int IDMisura(string Misura) { i. int IDM = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblUnitàDiMisura WHERE

tblUnitàDiMisura.Misura = '" + Misura + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDM = (int)leggi["IDMisura"]; vii. con.Close();

viii. return IDM; ix. }

Qui notiamo però le seguenti funzioni private int leggiIDReagenteDF(),private int

IDLocazione(string Locazione), private int IDFornitore(string Fornitore) e private int

IDMisura(string Misura). Infatti qui inseriamo dei nuovi dati riguardanti il contenitore e il

reagente (la vera e propria sostanza). Come già anticipato le tblReagenteDF e tblReagenteDV

hanno chiavi primaria che è anche chiave esterna. Ciò significa che quando inseriamo un nuovo

record devo inserirlo contemporaneamente anche nell’altra tabella, dove le chiavi primarie

devono coincidere.

La funzione leggiIDReagenteDF restituisce la chiave primaria della tblReagenteDF in base alla

chiave esterna della sostanza chimica. Le altre funzioni sono di ovvio significato : devono in

base alla stringa data recuperare il valore della corrispondente chiave primaria.

Quando invece selezioniamo un reagente e premiamo il bottone Elimina allora quello che

accade e che compare un nuovo Form, più piccolo, che chiede la conferma dell’Eliminazione.

Se si preme il tasto “Si”allora il codice che viene eseguito è il seguente :

Page 91: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

91

1. private void button1_Click(object sender, EventArgs e) a. {

i. // premuto il tatso SI ii. SqlCommand update = new SqlCommand(); iii. update.CommandType = CommandType.Text; iv. update.CommandText = "UPDATE tblReagenteDV SET [IDStato]= @IDS,

[QuantitàResidua]=@QS WHERE IDReagente = '" + ID + "'"; v. update.Parameters.AddWithValue("@IDS", 2); vi. update.Parameters.AddWithValue("@QS", 0); vii. update.Connection = con;

viii. con.Open(); ix. update.ExecuteNonQuery(); x. con.Close(); xi. MessageBox.Show("Reagente eliminato con succeesso!"); xii. AggiornaOp();

xiii. f2.dataGridView8.Rows[riga].Selected = true; xiv. f2.dataGridView8_MouseClick(f2.dataGridView8, f2.g); xv. DataTable dt = new DataTable(); xvi. f2.dataGridView6.ClearSelection();

xvii. f2.dataGridView7.DataSource = dt; xviii. f2.dataGridView4.ClearSelection();

xix. f2.dataGridView5.DataSource = dt; xx. f2.buttonPrelievoReagente.Enabled = false; xxi. f2.buttonDatiReso.Enabled = false;

xxii. Close(); b. }

private void AggiornaOp() {…}

L’eliminazione di una sostanza equivale da un’ Update nella tabella tblReagenteDV dove lo stato

della sostanza viene modificato e portato a 2 (chiave esterna che indica nella tblStato lo stato

Eliminato).

Gestione Sostanza Chimica

Figura 60 : Scheda Gestione Sostanza Chimica

Page 92: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

92

In questa scheda oltre che alla classica Ricerca della sostanza e del relativo salvataggio di dati in

Excel, possiamo Gestire i Sinonimi nonché Gestire le Sostanze vere e proprie. Questa parte è

raggiungibile solo dal administrator.

Premendo il bottone Inserisci sotto il primo datagridview si apre il seguente Form :

Figura 61 : Form Nuova Sostanza

Ci sono 4 textbox e 1 combobox. Il bottone Registra usa il seguente codice :

1. private void button1_Click(object sender, EventArgs e) a. {

i. if (textBox1.Text == "" || textBox2.Text == "" || textBox4.Text == "") MessageBox.Show("CAS,Nome e Formula sono campi obbligatori");

ii. else { 1. NumberFormatInfo provider = new NumberFormatInfo(); 2. provider.NumberDecimalSeparator = "."; 3. double massa = Convert.ToDouble(textBox3.Text, provider); 4. string query = "INSERT INTO tblSostanzaChimica (CAS,

NomeSostanza, MassaMolecolare, Formula, IDClasse) VALUES (@CAS, @NS, @Massa, @Form, @IDC)";

5. SqlCommand insert = new SqlCommand(query, con);

6. insert.Parameters.AddWithValue("@CAS", textBox1.Text); 7. insert.Parameters.AddWithValue("@NS", textBox2.Text); 8. insert.Parameters.AddWithValue("@Massa", massa); 9. insert.Parameters.AddWithValue("@Form", textBox4.Text); 10. insert.Parameters.AddWithValue("@IDC",

leggiIDClasse(comboBox1.Text));

11. con.Open(); 12. insert.ExecuteNonQuery(); 13. con.Close(); 14. MessageBox.Show("Sostanza chimica inserita con successo");

Page 93: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

93

15. Close(); 16. f2.caricagriglia10(); 17. f2.caricatutteg(); 18. }

b. }

2. private int leggiIDClasse(string Classe) {

i. int IDC = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblClasse WHERE

tblClasse.Classe = '" + Classe + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDC = (int)leggi["IDClasse"]; vii. con.Close();

viii. return IDC; ix. }

L’inserimento dati da oggetti SqlComand è standard. Notiamo però la funzione (riga 2) private

int leggiIDClasse(string Classe) . Questa funzione prende come parametro d’ingresso una

stringa , chiamate Classe, e ritorna la chiave primaria del record in cui quella stringa Classe è

registrata. La stringa Classe rappresenta la stringa visualizzata nella ComboBox.

Invece premendo il bottone Elimina viene eseguito il seguente codice :

1. private void button29_Click(object sender, EventArgs e) a. {

i. SqlCommand cmd = new SqlCommand(); ii. cmd.CommandType = CommandType.Text; iii. cmd.CommandText = "DELETE tblSostanzaChimica WHERE IDSostanzaChimica

='" + dataGridView10.SelectedRows[0].Cells[0].Value.ToString() + "'"; iv. cmd.Connection = con; v. con.Open(); vi. cmd.ExecuteNonQuery(); vii. con.Close();

viii. MessageBox.Show("Sostanza chimica eliminata con successo"); ix. }

In questo caso abbiamo un DELETE, ma come per l’insert e l’update la sintassi è molto simile.

Se invece si preme il bottone Aggiungi sotto il datagridview dei Sinonimi appare questo Form :

Page 94: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

94

Figura 62 : Form Aggiungi Sinonimo

Abbiamo 1 textbox e 1 ComboBox. Inoltre abbiamo il bottone Nuova Fonte per inserire i dati

della nuova Fonte. Il Form che appare cliccando su Nuova Fonte è il seguente :

Figura 63 : Form Nuova Fonte

Page 95: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

95

Abbiamo 2 texbox. Il bottone Registra ha il seguente codice :

2. private void button1_Click(object sender, EventArgs e) 3. { 4. reg = true; 5. string query = "INSERT INTO tblFonte (NomeFonte, urlFonte) VALUES (@NF, @url)"; 6. SqlCommand insert = new SqlCommand(query, con);

7. insert.Parameters.AddWithValue("@NF", textBox1.Text); 8. insert.Parameters.AddWithValue("@url", textBox2.Text); 9. con.Open(); 10. insert.ExecuteNonQuery(); 11. con.Close(); 12. MessageBox.Show("Nuova fonte inserita con successo");

13. Close();

14. }

Mentre il bottone Registra del Form Aggiungi Sinonimo ha il seguente codice

1. private void button2_Click(object sender, EventArgs e)//registra nuovo sinonimo a. {

i. string query = "INSERT INTO tblSinonimo (IDSostanzaChimica, Sinonimo, IDSinonimoFonte) VALUES (@IDS, @Sin, @IDSinF)";

ii. SqlCommand insert = new SqlCommand(query, con);

iii. insert.Parameters.AddWithValue("@IDS", Int32.Parse(tempID)); iv. insert.Parameters.AddWithValue("@Sin", textBox1.Text); v. insert.Parameters.AddWithValue("@IDSinF", leggiID(comboBox1.Text)); vi. con.Open(); vii. insert.ExecuteNonQuery();

viii. con.Close(); ix. MessageBox.Show("Dati di sinonimo inseriti con successo"); x. Close();

b. }

2. private int leggiID(string Fonte) {

i. int ID = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblFonte WHERE

tblFonte.NomeFonte = '" + Fonte + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) ID = (int)leggi["IDFonte"]; vii. con.Close();

viii. return ID;

b. }

Codice molto simile a quello visto fin’ora dalla spiegazione ovvia.

Il bottone Modifica , modifica il sinonimo selezionato e fa aprire il form come in figura :

Page 96: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

96

Figura 64 : Form Modifica Sinonimo

Il bottone Modifica ha il seguente codice :

1. private void button1_Click(object sender, EventArgs e) a. {

i. if (textBox1.Text == "") MessageBox.Show("Non puoi inserire un sinonimo vuoto");

ii. else { iii. SqlCommand update = new SqlCommand(); iv. update.CommandType = CommandType.Text; v. update.CommandText = "UPDATE tblSinonimo SET [Sinonimo]=@Sin,

[IDSinonimoFonte]=@IDSF WHERE IDSinonimo = '" + leggiIDSin(tempSin) + "'";

vi. update.Parameters.AddWithValue("@Sin", textBox1.Text); vii. update.Parameters.AddWithValue("@IDSF",

leggiIDSinFont(comboBox1.Text)); viii. update.Connection = con;

ix. con.Open(); x. update.ExecuteNonQuery(); xi. con.Close(); xii. MessageBox.Show("Sinonimo modificato con successo");

xiii. f2.dataGridView10.Rows[riga].Selected = true; xiv. f2.dataGridView10_MouseClick(f2.dataGridView10, f2.l); xv. Close(); xvi. }

b. }

2. private int leggiIDSin(string Sinonimo) { i. int ID = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblSinonimo WHERE

tblSinonimo.Sinonimo = '" + Sinonimo + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) ID = (int)leggi["IDSinonimo"];

Page 97: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

97

vii. con.Close(); viii. return ID;

b. } 3. private int leggiIDSinFont(string Fonte) {

i. int IDSF = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblFonte WHERE

tblFonte.NomeFonte = '" + Fonte + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDSF = (int)leggi["IDFonte"]; vii. con.Close();

viii. return IDSF;

b. }

Quindi nella riga viene fatto l’update della tabella tblSinonimo in base ai dati recuperati nel form.

La funzione di riga2, private int leggiIDSin(string Sinonimo) recupera ID del Sinonimo dato

come parametro d’ingresso che serve come condizione per vedere in quale record della tabella

andare ad aggiornare il dato in tabella, mentre la funzione private int leggiIDSinFont(string

Fonte) recupera l’ID della tabella tblFonte in base alla stringa data come parametro d’ingresso

(che è il testo della combobox in quel istante) necessario quando si modifica la Fonte nella

combobox. Infatti l’ID recuperato da quest’ultma funzione serve per andare ad aggiornare la

chiave esterna nella tabella tblSinonimo (riga 1.a.vii).

Invece il bottone Elimina fa comparire questa messagebox :

Figura 65 : Eliminazione Sinonimo

Page 98: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

98

Il codice che esegue l’eliminazione è il seguente :

1. private void button18_Click(object sender, EventArgs e)

a. { i. SqlCommand cmd = new SqlCommand(); ii. cmd.CommandType = CommandType.Text; iii. cmd.CommandText = "DELETE tblSinonimo WHERE IDSinonimo ='" +

leggiIDSin(dataGridView11.SelectedRows[0].Cells[1].Value.ToString())+"'";

iv. cmd.Connection = con; v. con.Open(); vi. cmd.ExecuteNonQuery(); vii. con.Close();

viii. MessageBox.Show("Sinonimo eliminato con successo"); ix. int riga

=dataGridView10.Rows.GetFirstRow(DataGridViewElementStates.Selected); x. dataGridView10.Rows[riga].Selected = true; xi. dataGridView10_MouseClick(dataGridView10,l);

b. }

Vediamo che l’elimnazione vera e propria viene eseguita nella riga 1.a.iii nella quale viene

eliminato il record avente ID uguale a quello dato dalla funzione leggiIDSin che come parametro

d’ingresso accetta una stringa , in questo caso data dalla seconda cella del datagridview11 della

riga selezionata. Quello che segue poi è il MessageBox , come si vede in figura, e l’aggiornamento

del datagridview corrispondente.

Come si vede da tutte le figure di ogni scheda, c’è la possibilità di Ricerca di una Sostanza in base al

CAS, Nome e Formula. I checkbox sono mutualmente esclusivi. Ma in questa scheda è data la

possibilità di Ricerca anche in base al Sinonimo. Infatti può capitare spesso che si inserisca

correttamente il nome della sostanza , poi si inserisca anche qualche sinonimo. Quando si fa una

ricerca molte volte non ci si ricorda il nome della sostanza correttamente e si fa uso dei sinonimi

proprio per questo. La possibilità di ricerca per sinonimo è stata aggiunta in modo automatico

durante ad esempio la selezione del criterio di ricerca per Nome e nel caso in cui non ci siano

risultati nella griglia principale. Il codicedel bottone Ricerca in questo caso è il seguente :

1. private void button9_Click(object sender, EventArgs e)

a. { i. if (checkBox20.Checked == true && checkBox19.Checked == false &&

checkBox18.Checked == false && checkBox33.Checked ==false) ii. { iii. //ric per CAS iv. con.Open(); v. SqlCommand cmd = con.CreateCommand(); vi. cmd.CommandType = CommandType.Text; vii. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula, tblClasse.Classe FROM tblSostanzaChimica LEFT JOIN tblClasse ON tblClasse.IDClasse = tblSostanzaChimica.IDClasse WHERE tblSostanzaChimica.CAS LIKE '%" + textBox13.Text + "%'";

viii. cmd.ExecuteNonQuery();

Page 99: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

99

ix. con.Close(); x. DataTable dt = new DataTable(); xi. SqlDataAdapter da = new SqlDataAdapter(cmd); xii. da.Fill(dt);

xiii. dataGridView10.DataSource = dt; xiv. } xv. else if (checkBox20.Checked == false && checkBox19.Checked == true &&

checkBox18.Checked == false && checkBox33.Checked == false) xvi. {//ricerca per Nome

xvii. con.Open(); xviii. SqlCommand cmd = con.CreateCommand();

xix. cmd.CommandType = CommandType.Text; xx. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula, tblClasse.Classe FROM tblSostanzaChimica LEFT JOIN tblClasse ON tblClasse.IDClasse = tblSostanzaChimica.IDClasse WHERE tblSostanzaChimica.NomeSostanza LIKE '%" + textBox13.Text + "%'";

xxi. cmd.ExecuteNonQuery(); xxii. con.Close(); xxiii. DataTable dt = new DataTable(); xxiv. SqlDataAdapter da = new SqlDataAdapter(cmd); xxv. da.Fill(dt);

xxvi. dataGridView10.DataSource = dt; xxvii. if (dataGridView10.RowCount == 0) {

1. con.Open(); 2. SqlCommand cmd1 = con.CreateCommand(); 3. cmd1.CommandType = CommandType.Text; 4. cmd1.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula, tblClasse.Classe FROM tblSostanzaChimica LEFT JOIN tblClasse ON tblClasse.IDClasse = tblSostanzaChimica.IDClasse LEFT JOIN tblSinonimo ON tblSinonimo.IDSostanzaChimica = tblSostanzaChimica.IDSostanzaChimica WHERE tblSinonimo.Sinonimo LIKE '%" + textBox13.Text + "%'";

5. cmd1.ExecuteNonQuery(); 6. con.Close(); 7. DataTable dt1 = new DataTable(); 8. SqlDataAdapter da1 = new SqlDataAdapter(cmd1); 9. da1.Fill(dt1); 10. dataGridView10.DataSource = dt1; 11. if (dataGridView10.RowCount == 0) MessageBox.Show("Nessun

risultato nè per Nome nè per Sinonimo"); 12. }

xxviii. } xxix. else if (checkBox20.Checked == false && checkBox19.Checked == false &&

checkBox18.Checked == true && checkBox33.Checked == false) xxx. {//ric per formula

xxxi. con.Open(); xxxii. SqlCommand cmd = con.CreateCommand(); xxxiii. cmd.CommandType = CommandType.Text; xxxiv. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula, tblClasse.Classe FROM tblSostanzaChimica LEFT JOIN tblClasse ON tblClasse.IDClasse = tblSostanzaChimica.IDClasse WHERE tblSostanzaChimica.Formula LIKE '%" + textBox13.Text + "%'";

xxxv. cmd.ExecuteNonQuery(); xxxvi. con.Close(); xxxvii. DataTable dt = new DataTable(); xxxviii. SqlDataAdapter da = new SqlDataAdapter(cmd); xxxix. da.Fill(dt);

xl. dataGridView10.DataSource = dt; xli. }

Page 100: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

100

xlii. else if (checkBox20.Checked == false && checkBox19.Checked == false && checkBox18.Checked == false && checkBox33.Checked == true) {

xliii. //ric per sinonimo xliv. con.Open(); xlv. SqlCommand cmd = con.CreateCommand();

xlvi. cmd.CommandType = CommandType.Text; xlvii. cmd.CommandText = "SELECT tblSostanzaChimica.CAS,

tblSostanzaChimica.NomeSostanza, tblSostanzaChimica.Formula, tblClasse.Classe FROM tblSostanzaChimica LEFT JOIN tblClasse ON tblClasse.IDClasse = tblSostanzaChimica.IDClasse LEFT JOIN tblSinonimo ON tblSinonimo.IDSostanzaChimica = tblSostanzaChimica.IDSostanzaChimica WHERE tblSinonimo.Sinonimo LIKE '%" + textBox13.Text + "%'";

xlviii. cmd.ExecuteNonQuery(); xlix. con.Close();

l. DataTable dt = new DataTable(); li. SqlDataAdapter da = new SqlDataAdapter(cmd); lii. da.Fill(dt);

liii. dataGridView10.DataSource = dt; liv. } lv. else MessageBox.Show("Errore criterio di ricerca");

b. }

Analizziamo la riga n.1.a.xxvii. Quando il datagridview10 non produce alcun risultato (in questo

caso nessun risultato per Nome) allora ricerca per Sinonimo. In caso di nessun risultato neanche

per Sinonimo, avvisa con un MessageBox.

Gestione Utenti

La scheda di Gestione Utenti invece è la seguente :

Figura 66 : Gestione Utenti

Page 101: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

101

I bottoni Modifica o Nuovo aprono il seguente Form :

Figura 67 : Form Utente

Vediamo prima l’evento Load del Form :

1. private void Utente_Load(object sender, EventArgs e){

i. con.Open(); ii. SqlDataReader leggi = null; iii. SqlCommand cmd1 = new SqlCommand("SELECT * FROM tblLaboratorio", con); iv. leggi = cmd1.ExecuteReader(); v. while (leggi.Read()) comboBox1.Items.Add(leggi["NomeLaboratorio"]); vi. con.Close(); vii. if (ut == true) {

viii. //nuovo utente ix. comboBox1.SelectedText = ""; x. } xi. else { xii. //modifica utente

xiii. comboBox1.SelectedText = laboratorio; xiv. textBox1.Text = nome; xv. textBox1.ReadOnly = true; xvi. textBox2.Text = cognome;

xvii. textBox2.ReadOnly = true; xviii. textBox3.Text = username;

xix. textBox4.Text = password; xx. if (abilitazione == "Administrator") checkBox2.Checked = true; xxi. else if (abilitazione == "User") checkBox1.Checked = true;

xxii. else checkBox3.Checked = true; xxiii. }

b. }

Page 102: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

102

Dal evento Load vediamo subito che viene fatto test sulla variabile ut. Questa variabile proviene

dal Form principale e viene passata attraverso i metodi getter-setter. Infatti se questa variabile

vale true (quando si preme il bottone Aggiungi del Form principale)allora bisogna aggiungere un

nuovo utente, altrimenti bisogna modificarlo (riga 1.vii e 1.xi).

Il bottone Registra ha il seguente codice :

1. private void button1_Click(object sender, EventArgs e) {

i. if (checkBox1.Checked == true && checkBox2.Checked == true ||

checkBox2.Checked == true && checkBox3.Checked == true || checkBox1.Checked == true checkBox3.Checked == true) MessageBox.Show("Utente, non correttamente");

ii. else { iii. int abilita; iv. if (checkBox2.Checked == true) abilita = 1;//admin v. else if (checkBox1.Checked == true) abilita = 2; //user vi. else abilita = 3;//non abilitato

1. if (ut == true) 2. {//nuovo utente

3. string query = "INSERT INTO tblUtente (Username, Password,

NomeUtente, CognomeUtente, IDAbilitazione, IDLaboratorio, IDStato ) VALUES (@User, @Passwd, @Nome, @Cognome, @IDA, @IDL, @IDS)";

4. SqlCommand insert = new SqlCommand(query, con); 5. insert.Parameters.AddWithValue("@User", textBox3.Text); 6. insert.Parameters.AddWithValue("@Passwd", textBox4.Text); 7. insert.Parameters.AddWithValue("@Nome", textBox1.Text); 8. insert.Parameters.AddWithValue("@Cognome", textBox2.Text); 9. insert.Parameters.AddWithValue("@IDA", abilita); 10. insert.Parameters.AddWithValue("@IDL,

leggiIDLaboratorio(comboBox1.Text)); 11. insert.Parameters.AddWithValue("@IDS", 1); 12. con.Open(); 13. insert.ExecuteNonQuery(); 14. con.Close(); 15. MessageBox.Show("Nuovo utente registrato con successo"); 16. } 17. else {//modifica utente 18. SqlCommand update = new SqlCommand(); 19. update.CommandType = CommandType.Text; 20. update.CommandText = "UPDATE tblUtente SET [Username]= @User,

[Password]=@Passwd, [IDAbilitazione]=@IDA, [IDLaboratorio]=@IDL, [IDStato]=@IDS WHERE NomeUtente = '" + textBox1.Text + "' AND CognomeUtente = '"+textBox2.Text+"'";

21. update.Parameters.AddWithValue("@User", textBox3.Text); 22. update.Parameters.AddWithValue("@Passwd", textBox4.Text); 23. update.Parameters.AddWithValue("@IDA", abilita); 24. update.Parameters.AddWithValue("@IDL",

leggiIDLaboratorio(comboBox1.Text)); 25. update.Parameters.AddWithValue("@IDS", 1); 26. update.Connection = con; 27. con.Open(); 28. update.ExecuteNonQuery(); 29. con.Close(); 30. MessageBox.Show("Dati utente modificati con successo");

Page 103: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

103

31. } vii. f2.button33_Click(f2.button33, f2.r);

viii. Close(); ix. }

b. } 2. private int leggiIDLaboratorio(string Laboratorio) {

i. int IDL = 0; ii. con.Open(); iii. SqlDataReader leggi = null; iv. SqlCommand cmd = new SqlCommand("SELECT * FROM tblLaboratorio WHERE

tblLaboratorio.NomeLaboratorio = '" + Laboratorio + "'", con); v. leggi = cmd.ExecuteReader(); vi. while (leggi.Read()) IDL = (int)leggi["IDLaboratorio"]; vii. con.Close();

viii. return IDL;

ix. }

Anche qui come in precedenza notiamo che in base al valore della variabile booleana ut o

inseriamo un nuovo utente, oppure lo modifichiamo. La funzione leggiIDLaboratorio riceve la

stringa di parametro che è il nome di laboratorio (riga 1.vi.10 e riga 1.vi.24) e nella tabella

tblLaboratorio recupera l’ID corrispondente.

Reportistica

Questa parte è quella più importante per un’utente. Infatti qui l’utente può attraverso filtri additivi

ricercare tutte le informazioni possibili. I criteri di ricerca sono così definiti : in base al operazione,

in base alla sostanza chimica, in base al utente e in base alla data.

Figura 68 : Scheda Reportistica

Page 104: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

104

Il bottone Ricerca ha il seguente codice :

1. private void button35_Click(object sender, EventArgs e) { 2. if (checkBox26.Checked == true && checkBox27.Checked == false && checkBox28.Checked

== false && checkBox29.Checked == false) { 3. //ricerca solo per Operazione 4. con.Open(); 5. SqlCommand cmd = con.CreateCommand(); 6. cmd.CommandType = CommandType.Text; 7. cmd.CommandText = "SELECT tblOperazione.Operazione, tblOperazione.Data,

tblSostanzaChimica.CAS, tblSostanzaChimica.NomeSostanza, tblReagenteDV.Acquirente, tblReagenteDV.QuantitàResidua, tblUnitàDiMisura.Misura,tblLocazione.NomeLocazione, tblOperazione.Locazionepassata,tblUtente.NomeUtente, tblUtente.CognomeUtente FROM tblOperazione INNER JOIN tblReagenteDF ON tblReagenteDF.IDreagente = tblOperazione.IDreagente INNER JOIN tblSostanzaChimica ON tblSostanzaChimica.IDSostanzaChimica = tblReagenteDF.IDreagente INNER JOIN tblUtente ON tblOperazione.Username = tblUtente.Username INNER JOIN tblReagenteDV ON tblReagenteDV.IDReagente = tblOperazione.IDreagente INNER JOIN tblUnitàDiMisura ON tblUnitàDiMisura.IDMisura = tblReagenteDF.IDMisura INNER JOIN tblLocazione ON tblLocazione.IDLocazione = tblReagenteDV.IDlocazione WHERE tblOperazione.Operazione = '" + comboBox2.Text + "' ";

8. cmd.ExecuteNonQuery(); 9. DataTable dt = new DataTable(); 10. SqlDataAdapter da = new SqlDataAdapter(cmd); 11. da.Fill(dt); 12. con.Close(); 13. dataGridView17.DataSource = dt; 14. dataGridView17.Columns[7].HeaderText = "Locazione attuale";

i. if (dataGridView17.Rows.Count == 0) { ii. DataTable dt1 = new DataTable(); iii. dataGridView17.DataSource = dt1; iv. MessageBox.Show("Nessun risultato!"); v. } vi. else {

1. dataGridView17.Enabled = true; 2. dataGridView17.Rows[0].Selected =true; 3. button36.Enabled = true; 4. }

vii. } viii. else if (checkBox26.Checked == false && checkBox27.Checked == true &&

checkBox28.Checked == false && checkBox29.Checked == false) { ix. //ricerca solo in base alla sostanza selezionata x. con.Open(); xi. SqlCommand cmd = con.CreateCommand(); xii. cmd.CommandType = CommandType.Text;

xiii. cmd.CommandText = "SELECT tblOperazione.Operazione, tblOperazione.Data, tblSostanzaChimica.CAS, tblSostanzaChimica.NomeSostanza, tblReagenteDV.Acquirente, tblReagenteDV.QuantitàResidua, tblUnitàDiMisura.Misura, tblLocazione.NomeLocazione, tblOperazione.Locazionepassata, tblUtente.NomeUtente, tblUtente.CognomeUtente FROM tblOperazione INNER JOIN tblReagenteDF ON tblReagenteDF.IDreagente = tblOperazione.IDreagente INNER JOIN tblReagenteDV ON tblReagenteDV.IDReagente = tblReagenteDF.IDreagente INNER JOIN tblSostanzaChimica ON tblSostanzaChimica.IDSostanzaChimica = tblReagenteDF.IDSostanzaChimica INNER JOIN tblUtente ON tblOperazione.Username = tblUtente.Username INNER JOIN tblUnitàDiMisura ON tblUnitàDiMisura.IDMisura = tblReagenteDF.IDMisura INNER JOIN tblLocazione ON tblLocazione.IDLocazione = tblReagenteDV.IDLocazione WHERE tblOperazione.IDreagente = '" + dataGridView18.SelectedRows[0].Cells[0].Value.ToString() + "' ";

xiv. cmd.ExecuteNonQuery(); xv. DataTable dt = new DataTable();

Page 105: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

105

xvi. SqlDataAdapter da = new SqlDataAdapter(cmd); xvii. da.Fill(dt); xviii. con.Close();

xix. dataGridView17.DataSource = dt; xx. dataGridView17.Columns[7].HeaderText = "Locazione attuale"; xxi. if (dataGridView17.Rows.Count == 0){

1. DataTable dt1 = new DataTable(); 2. dataGridView17.DataSource = dt1; 3. MessageBox.Show("Nessun risultato!");

xxii. } xxiii. else{

1. dataGridView17.Enabled = true; 2. dataGridView17.Rows[0].Selected = true; 3. button36.Enabled = true; 4. }

xxiv. } xxv. else if (checkBox26.Checked == false && checkBox27.Checked == false &&

checkBox28.Checked == true && checkBox29.Checked == false) { xxvi. //ricerca solo per utente xxvii. int i; xxviii. i = dataGridView16.SelectedRows.Count; xxix. int j = 0; xxx. DataTable dt1 = new DataTable();

xxxi. while(j<i) { xxxii. con.Open(); xxxiii. SqlCommand cmd = con.CreateCommand(); xxxiv. cmd.CommandType = CommandType.Text; xxxv. cmd.CommandText = "SELECT tblOperazione.Operazione, tblOperazione.Data,

tblSostanzaChimica.CAS, tblSostanzaChimica.NomeSostanza, tblReagenteDV.Acquirente, tblReagenteDV.QuantitàResidua, tblUnitàDiMisura.Misura, tblLocazione.NomeLocazione , tblOperazione.Locazionepassata, tblUtente.NomeUtente, tblUtente.CognomeUtente FROM tblOperazione INNER JOIN tblReagenteDF ON tblReagenteDF.IDreagente = tblOperazione.IDreagente INNER JOIN tblSostanzaChimica ON tblReagenteDF.IDSostanzaChimica = tblSostanzaChimica.IDSostanzaChimica INNER JOIN tblReagenteDV ON tblReagenteDV.IDReagente = tblReagenteDF.IDreagente INNER JOIN tblUnitàDiMisura ON tblUnitàDiMisura.IDMisura = tblReagenteDF.IDMisura INNER JOIN tblLocazione ON tblLocazione.IDLocazione = tblReagenteDV.IDLocazione INNER JOIN tblUtente ON tblOperazione.Username = tblUtente.Username WHERE tblOperazione.Username = '" + dataGridView16.SelectedRows[j].Cells[2].Value.ToString() + "' ";

xxxvi. cmd.ExecuteNonQuery(); xxxvii. DataTable dt = new DataTable(); xxxviii. SqlDataAdapter da = new SqlDataAdapter(cmd); xxxix. da.Fill(dt);

xl. con.Close(); xli. dt1.Merge(dt);

xlii. dataGridView17.DataSource = dt1; xliii. dt.Clear(); xliv. j++; xlv. }

xlvi. dataGridView17.Columns[7].HeaderText = "Locazione attuale"; xlvii. if (dataGridView17.Rows.Count == 0){

1. DataTable dt2 = new DataTable(); 2. dataGridView17.DataSource = dt2; 3. MessageBox.Show("Nessun risultato!");

xlviii. } xlix. else

l. { 1. dataGridView17.Enabled = true;

Page 106: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

106

2. dataGridView17.Rows[0].Selected = true; 3. button36.Enabled = true;

li. } lii. }

liii. else if (checkBox26.Checked == false && checkBox27.Checked == false && checkBox28.Checked == false && checkBox29.Checked == true)

liv. {//ricerca solo per data lv. DateTime d1 = dateTimePicker1.Value; lvi. DateTime d2 = dateTimePicker2.Value;

lvii. con.Open(); lviii. SqlCommand cmd = con.CreateCommand();

lix. cmd.CommandType = CommandType.Text; lx. cmd.CommandText = "SELECT tblOperazione.Operazione, tblOperazione.Data,

tblSostanzaChimica.CAS, tblSostanzaChimica.NomeSostanza, tblReagenteDV.Acquirente, tblReagenteDV.QuantitàResidua, tblUnitàDiMisura.Misura, tblLocazione.NomeLocazione , tblOperazione.Locazionepassata, tblUtente.NomeUtente, tblUtente.CognomeUtente FROM tblOperazione INNER JOIN tblReagenteDF ON tblOperazione.IDreagente = tblReagenteDF.IDreagente INNER JOIN tblSostanzaChimica ON tblSostanzaChimica.IDSostanzaChimica = tblReagenteDF.IDSostanzaChimica INNER JOIN tblReagenteDV ON tblReagenteDV.IDReagente = tblReagenteDF.IDreagente INNER JOIN tblUnitàDiMisura ON tblUnitàDiMisura.IDMisura = tblReagenteDF.IDMisura INNER JOIN tblLocazione ON tblLocazione.IDLocazione = tblReagenteDV.IDLocazione INNER JOIN tblUtente ON tblOperazione.Username = tblUtente.Username WHERE ( tblOperazione.Data BETWEEN @DA AND @A ) ";

lxi. cmd.Parameters.Add("@DA", d1); lxii. cmd.Parameters.Add("@A", d2); lxiii. cmd.ExecuteNonQuery(); lxiv. DataTable dt = new DataTable(); lxv. SqlDataAdapter da = new SqlDataAdapter(cmd);

lxvi. da.Fill(dt); lxvii. con.Close(); lxviii. dataGridView17.DataSource = dt; lxix. dataGridView17.Columns[7].HeaderText = "Locazione attuale"; lxx. if (dataGridView17.Rows.Count == 0){

1. DataTable dt1 = new DataTable(); 2. dataGridView17.DataSource = dt1; 3. MessageBox.Show("Nessun risultato!");

lxxi. } lxxii. else lxxiii. {

1. dataGridView17.Enabled = true; 2. dataGridView17.Rows[0].Selected = true; 3. button36.Enabled = true;

lxxiv. } lxxv. } lxxvi. }

Qui viene riportato per semplicità soltanto il codice per ricerca singola di filtri. Quando invece c’è

una ricerca con filtri additivi, allora l’unica cosa che cambia sostanzialmente sono le condizioni

della query dove conle parole chiavi WHERE e AND si aggiungono condizioni. Quello che viene

fatto è questo : prima viene eseguita la query in base alla condizioni poste dei singoli filtri. Poi nel

caso non ci siano risulati, compare un messaggio che indica che non ci sono risulati, altrimenti

viene popolata la griglia sottostante con i risultati. L’Header della cella numero 7 viene chiamata

come “Locazione attuale” (per distinguerla dalla “Locazione passata” che può essere anche nulla

Page 107: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

107

in certi casi), questo è fondamentale per distinguerla durante le operazioni di Spostamento. Se ci

sono dei risultati allora si attiva la possibilità di clicclare sul bottone Salva in Excel.

Page 108: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

108

CONCLUSIONI

Gli obbiettivi che il progetto si era posto all’inizio sono stati raggiunti. Si è partiti dalla analisi delle

prestazioni di un prototipo e, in base alle considerazioni e suggerimenti degli utenti, si è addivenuti

ad una rivisitazione del progetto originale per tenere conto delle mutate condizioni sia normative

che di procedure, anche dovute alla fusione di diversi dipartimenti in un unico dipartimento.

L’applicazione sviluppata consiste in un data base, gestito da un DBMS MS-SQL server 2012 e da

un applicativo Windows Forms sviluppato in Visual studio.

In questo progetto sono state sviluppate 14 tabelle. Nella tabella principale tblSostanzaChimica

sono presenti 5000 record. Sono stati creati 15 Form. Sono presenti 11536 righe di codice.

Sono soddisfatto dell’esperienza che ho svolto. Mi ha permesso di capire intanto quanto sia

complicato gestire ambienti con tante informazioni e quanto sia complicato analizzare progetti da

migliorare, tenendo conto che l’utente finale ha bisogno continuamente di nuove specifiche anche

dettate dal cambiamento del mercato.

Il progetto non è attualmente ancora operativo, ma è in fase di testing. Superata questa fase

andrà sicuramente ad aiutare a gestire il personale del dipartimento nella gestione delle

informazioni delle sostanze chimiche. Inoltre, il prodotto potrebbe essere adottato da altri

dipartimenti dell’Ateneo per facilitare la gestione dei reagentari.

Page 109: Progetto e sviluppo di un’applicazione per la gestione di un reagentario per reagenti chimici

109

DEDICA

Mesi di lavoro per portare a termine questa tesi di laurea. Dedicarla a solo una persona o a due,

non avrebbe senso. Dedicarla a chi mi vuole bene, a chi mi ha voluto bene e ad esempio non c’è più

e a chi mi vorrà bene invece è sensato e giusto, ma senza fare nomi. Accettare le ingiustizie e le

avversità come se fossero una sfida per cercare di superarle.

Nei miei anni universitari ho conosciuto tante persone nuove, la mia conoscenza si è ampliata sia in

termini di amicizie che in termini di sapienza. Questo lo devo all’unviersità.

Grazie genitori, grazie amici e grazie università. Se oggi sono quello che sono lo devo soprattutto a

voi! Questa tesi ed li mio lavoro lo dedico a voi!!!