Press "Enter" to skip to content

13 – Lavorare con i dati – UserDb Correggiamo un errore

Ringrazio Paolo, uno di coloro che seguono questa serie di articoli per aver trovato e corretto un errore nel codice dell’articolo che mostrava l’uso delle librerie aggiuntive per Access e SQLite che trovate a questo indirizzo. Si tratta di un tipico errore che nasconde un altro errore, infatti, l’errore che Paolo ha rilevato è il seguente:

Nel codice del RadioButton che gestisce il database SQLite, c’era scritto questo:

IsChecked="{Binding UseSSqlite, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

In questo codice, il nome della property in binding UseSSqlite è sbagliato, infatti la property si chiama UseSQLite, pertanto il codice corretto è:

IsChecked="{Binding UseSQLite, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

Questo significa che nell’esempio, selezionando quel radiobutton in realtà si selezionava il database di default, SQL Server e quindi tutto sembrava funzionare.

Se invece effettuiamo la correzione, verrà sollevata un eccezione:

01_error_00

Questa eccezione si verifica perché corretto il primo errore, abbiamo portato alla luce un errore fondamentale, se ben ricordate, nella libreria Data Provider SQLiteD’p, abbiamo referenziato la libreria System.Data.SQLite.dll e oltre a ciò non abbiamo incluso nel progetto la libreria SQLite.Interop.dll. Perché il nostro progetto UserDp.exe possa funzionare, anche in questo progetto dobbiamo referenziare le due librerie. Quindi procediamo a fare quello che è necessario:

01_error_add_sqlite_01

Spostiamoci sul progetto UsersDB, e facciamo tasto destro Add, Existing Item, ed andiamo a cercare la DLL di Interoperabilità da includere nel progetto:

01_error_add_sqlite_02

Ci spostiamo in C:\Program Files (x86)\System.Data.SQLite\2013\bin indichiamo a Visual Studio che vogliamo vedere tutti i files, e selezioniamo SQLite.Interop.dll.

01_error_add_sqlite_03

Troveremo la DLL inserita nei files di progetto, spostiamoci in basso sulla finestra delle Properties e selezioniamo il Copy Always in modo che sia copiata automaticamente sulla cartella del nostro progetto, così che il nostro eseguibile la trovi quando serve.

Aggiungiamo anche il reference alla libreria dotnet vera e propria quindi spostiamoci su References, Add Reference clicchiamo sul pulsante Browse… e andiamo a selezionare System.Data.SQLite.dll.

01_error_add_sqlite_04

Selezioniamo la DLL di SQLite nella cartella di installazione.

01_error_add_sqlite_05

Adesso abbiamo aggiunto al progetto le 2 dll che ci serviranno per usare SQLite dal codice della nostra User Interface.

A questo punto, il caricamento e test del Data Provider di SQLite dovrebbe funzionare, invece ci sono ancora un paio di modifiche da fare, stavolta nel codice del Data Provider, dentro alla classe UsersDp che abbiamo definito nella libreria SQLite.

SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
	while (reader.Read())
	{
		User usr = new User();
		long userID = reader[User.FLD_ID].XxCheckDbNull<long>();
		usr.ID = (int)userID;
		usr.Computer = reader[User.FLD_Computer].XxCheckDbNull<string>();
		long loginType = reader[User.FLD_LoginType].XxCheckDbNull<long>();
		usr.LoginType = (TypeOfLogin)loginType;
		usr.Password = reader[User.FLD_Password].XxCheckDbNull<string>();
		usr.UserName = reader[User.FLD_UserName].XxCheckDbNull<string>();
		usr.WinDomain = reader[User.FLD_WinDomain].XxCheckDbNull<string>();
		usr.WinUser = reader[User.FLD_WinUser].XxCheckDbNull<string>();
		ret.Data.Add(usr);
	}
}

Il primo errore è dovuto al fatto che SQLite gestisce un numero limitato di Dati al suo interno, e il campo con auto incremento è chiamato INTEGER ma in realtà è un intero a 64 bit, quindi un long per C# pertanto non possiamo convertirlo direttamente in integer ma dobbiamo fare una conversione intermedia.

Stesso dicasi per LoginType, che abbiamo definito dello stesso tipo nella tabella del database, pertanto aggiungiamo le 2 righe di codice per poter fare una conversione esplicita da Long a int prima di creare lo User.

Il secondo errore, è dovuto al fatto che anche SQLite così come Access, non permette di selezionare il valore dell’IDENTITY appena aggiunta automaticamente dallo script di INSERT ma necessita l’esecuzione di una query specifica. Pertanto facciamo le seguenti modifiche in UsersDp:

private const string SQL_Insert = @"
	INSERT INTO [TbUsers]
				([WinUser]
				,[WinDomain]
				,[UserName]
				,[Computer]
				,[LoginType]
				,[Password])
			VALUES
				(@WinUser
				,@WinDomain
				,@UserName
				,@Computer
				,@LoginType
				,@Password )";
private const string SQL_GetIdentity = @"
		SELECT last_insert_rowid();
		";

Correggiamo lo script SQL di INSERT e creiamo lo script per leggere l’Identity appena inserito.

SQLiteParameter[] para = new SQLiteParameter[] {
		new SQLiteParameter("@WinUser", usr.WinUser.XxTryParseToDBNull<string>())
	,new SQLiteParameter("@WinDomain", usr.WinDomain.XxTryParseToDBNull<string>())
	,new SQLiteParameter("@UserName", usr.UserName.XxTryParseToDBNull<string>())
	,new SQLiteParameter("@Computer", usr.Computer.XxTryParseToDBNull<string>())
	,new SQLiteParameter("@LoginType", usr.LoginType.XxTryParseToDBNull<TypeOfLogin>(TypeOfLogin.None))
	,new SQLiteParameter("@Password", usr.Password.XxTryParseToDBNull<string>())
};
cmd.Parameters.Clear();
cmd.Parameters.AddRange(para);
 
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = SQL_GetIdentity;
object obj = cmd.ExecuteScalar();
if (obj != null)
{
	int id = -1;
	int.TryParse(obj.ToString(), out id);
	usr.ID = id;
	ret.Data.Add(usr);
}

Modifichiamo la porzione di codice nel ciclo for each per l’inserimento degli User nel database chiamando prima lo script Insert e poi lo script GetIdentity come abbiamo fatto anche nel data provider OleDb usato da Access.

A questo punto, anche SQLite funziona correttamente.

Ringrazio ancora Paolo per aver scoperto il problema e pubblico la versione aggiornata del codice di UsersDB con le correzioni qui commentate.

Potete scaricare il codice del progetto al seguente link:

Per qualsiasi domanda, curiosità, o se trovate un errore non esitate ad usare il