SQL Compact e le modifiche fantasma

Lo scrivo per ricordarmelo, visto che ci ho perso sin troppo tempo!

Per popolare il contenuto di un database ho creato una semplice applicazione console che legge un file csv.

Peccato che una volta eseguita l’applicazione, andata a buon fine senza alcun messaggio di errore, il database non contenesse alcuna modifica!

Rieseguendo l’applicazione, ogni volta era come fosse la prima volta. Ho pensato ad ogni possibile causa, anche perché facendo dei controlli all’interno dell’applicazione il database risultava effettivamente modificato.

Alla fine ho trovato la soluzione su Stackoverflow:

Quando si esegue un’applicazione all’interno di Visual Studio, la build fa una copia del file di database nella cartella bin/debug (o bin/release), ed è li che modifica il database, nonostante le impostazioni di connessione, che evidentemente cambia al volo.

I controlli successivi li facevo nel file del progetto (come da impostazioni di connessione) e non trovavo le modifiche che l’appicazione avrebbe dovuto apportare. Alla successiva esecuzione dell’applicazione, poiché il file aveva le proprietà di build impostate a “content” e “copy always”, nella cartella bin/debug veniva riscritto il file di database originale, ovvero senza modifiche, e tutto ricominciava da capo.

Davvero diabolico.

Da notare che facendo il deploy dell’applicazione ovviamente questo meccanismo non viene messo in atto (il contesto di esecuzione non muta, nel senso che il file di database e la cartella di esecuzione del runtime è quello di installazione) e quindi il problema non si pone.

SQL Compact - SKIP, TAKE and SQL emitted code

Per ottenere la lettura della n-esima riga di una tabella filtrata mediante Skip() e Take() basta eseguire una istruzione del tipo:
// Troviamo la row id della riga (randomSkip +1)-esima
int wordPK = (from w in dbContext.Words
              where w.Language == languageDictionaryCountryCode
              select w.Word_PK).Skip(n-1).Take(1).Single();

// Recuperiamo il testo della parola
string wordText = (from w in dbContext.Words
                   where w.Word_PK == wordPK
                   select w.Text).First();

e fin qui nulla di nuovo.

La cosa invece si fa interessante se andiamo a verificare il codice SQL emesso da LinqTo SQL per le diverse versioni di SQL Compact:

Se usiamo la versione 3.5 (o anche la 4.0, non fa differenza)  su un’applicazione non Windows Phone, otteniamo (grazie a LinqPad):

image

Com’è possibile notare, il codice SQL non fa uso di SKIP and TAKE, perché SQL Command non li supporta (vedi la documentazione Microsoft).

Ma questo non è del tutto vero, perche nel caso del SqlProvider utilizzato nei progetti Windows Phone 7.5 (Mango edition, tanto per intenderci), qualcosa è cambiato, anche se non ho trovato alcuna documentazione in merito.

Infatti, grazie alla possibilità di impostare la proprietà Log del DataContext ad una classe di tipo TextWriter, sono riuscito a recuperare il codice SQL emesso dal SqlProvider:

image

E’ evidente che lo SqlProvider è nuovo (versione 7.0.0.0) e che il motore di SQL Compact 3.5 WP7 Edition è in grado di gestire lo SKIP and TAKE nativamente (anche se le chiama OFFSET e NEXT).

Da tutto ciò si ricava la conferma che SQL Compact per Windows Phone ha un motore tutto nuovo, pur usando il formato dati versione 3.5, con alcune feature introdotte nella versione 4.0 .

That’s all folks!

UPDATE

Ho modificato il post per riflettere le ulterioni informazioni ricevute da Erik relativamente alla versione 4.0 che a differenza della 3.5 consente l’uso di OFFSET and FETCH.

Nota che nel commento di Erik il link non funziona ma l’url è giusto: http://msdn.microsoft.com/en-us/library/ms173288(v=SQL.110).aspx

UPDATE 29/01/2012

Il sorgente (in C#) del DebugTextwriter che Erik ha inserito nella versione 2.6.1 del suo utilissimo SQL CE Toolbox lo potete trovare nel mio post Visualizzare il comando SQL emesso da LinqToSQL.

«novembre»
domlunmarmergiovensab
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910