.NET 3.5 porta con sè un componente non troppo pubblicizzato denominato ADO.NET Synchronization Framework. L'idea fa parte di un ben più allargato Microsoft Synchronization Framework che vedrà la luce prossimamente come framework comune per la sincronizzazione di informazioni.
In questo post volevo sottolineare alcuni aspetti su cui si trovano informazioni contrastanti.
Gli oggetti supportati dal motore di sincronizzazione sono:
1) Table per tutte le tipologie di sincronizzazione
2) View per sincronizzazioni Snapshot e Download-Only
3) Il client appoggia i dati su SQL CE 3.5 e NON su SQL Express (almeno nella versione attuale)
4) Per default non vengono portati sul db locale i constraint di FOREIGN KEY, DEFAULT e UNIQUE.
Se occorre abilitare (e spesso è giustamente necessario) questi constraint lato client occorre modificare lo schema del DB sul client.
Questa operazione può essere effettuata utilizzando comandi DDL dopo la prima sincronizzazione dei dati, ma è consigliabile utilizzare l'oggetto SyncSchema.
In ogni caso è poi possibile modificare lo schema del DB lato client.
Se gli schemi sono diversi tenere in considerazione questa semplice regola:
Se viene replicato un campo (ovvero fa parte della SELECT di scaricamento dei dati) che non esiste sul client, il campo viene ignorato
Se il client ha un campo in più rispetto a quanto viene sincronizzato il campo verrà valorizzato con il suo DEFAULT se presente o con NULL.
5) Le colonne con proprietà ROWGUIDCOL vengono invece portare su SQLCE, ma senza la proprietà ROWGUIDCOL
6) Il client appoggia i dati su tabelle anche se viene sincronizzata una View...ovviamente
7) Non sono supportati gli oggetti fully-qualified: in pratica se abbiamo una tabella EstatesManagement.tabSalesman dove EstatesManagement rappresenta l'owner o lo schema. Occorre usare solo il nome della tabella.
8) Il framework fa parte di .NET 3.5 e non del .NET CF 3.5, quindi questo motore di sincronizzazione dei dati NON è utilizzabile (almeno nella versione attuale) da dispositivi Windows Mobile.
Si possono lanciare una sincronizzazione alla volta: anche eseguendo la sincronizzazione da un thread separati non è possibile lanciare sincronizzazioni contemporanee sugli stessi oggetti: in pratica se una tabella è oggetto di una replica in corso, non è possibile lanciare un'altra sincronizzazione in parallelo che utilizzi la stessa tabella.
Non è supportata la gestione dei campi Identity: in pratica il motore di sincronizzazione non ha meccanismi nativi per distribuire range di identity ai vari client.
Particolare attenzione deve essere posta nelle procedure di recovery a fronte di un restore dei DB: se il database server viene ripristinato da un restore le modifiche successive potrebbero non venir propagate ai vari client; il motivo è semplice: i client memorizzano solo nel database locale il valore di anchor ottenuto dall'ultima sincronizzaione: se un client era arrivato nella sincronizzazione precedente a recuperare le modifiche, dopo un restore sul server il client continua a chiedere le modifiche effettuate sul server successive all'ultima anchor . Quindi alcune modifiche effettuare sul server dopo il restore non vengono propagate al client in quanto l'anchor sul server ripristinato è inferiore all'anchor memorizzato sul client. Inoltre il client che ha effettuato l'upload di modifiche, dopo un restore del database server, si ritrova delle righe che sul server non esistono (visto che il DB è tornato ad una situazione precedente), e, ancora una volta il client pensa di averle sincronizzate visto che la sincronizzazione precedente era andata a buon fine.
Occorre quindi modificare il comportamento di default del motore di replica. Potremmo prendere spunto al processo utilizzato dalla Merge Replication di SQL Server: memorizzando anche sul server in una nostra tabella le anchor relative ai vari client. Durante ogni sincronizzazione, tramite una modifiche ai vari statement di select delle modifiche occorre incrociare l'anchor arrivata dal client con l'anchor presente sul server e utilizzare il valore minore per selezionare i record oggetto di modifica.
Come ultimo punto, nelle repliche partizionate per singolo utente conviene indicare sempre il parametro ClientId che solitamente si memorizza in un file di configurazione: non specificando questa proprietà il ClientSyncProvider valorizza questa proprietà in base alla chiave di registry HKCU\Software\Microsoft\Microsoft SQL Server Compact Edition\v3.5. Come sappiamo è bene non accedere al registry visto che sono richiesti permessi amministrativi per l'accesso.
Torneremo sull'argomento in altri post e in una sessione dedicata alla nostra DevCon 2008.