Thursday, July 17, 2008

Using SQL Express (or Standard/Enterprise) at the Client

First off, why would anyone want to use SQL Express (or one of it's bigger brothers) at the client? For us there's the case of a Site (grain silo) that wants offline functionality (if the link to head-office goes down), but still have changes on one PC be visible on all others. This is a perfect case for all the apps at that site to talk to a local SQL Server, and have a service running on the server that will sync with head-office when the connection is up.

We took a look at the SQL Express Client Synchronization using Sync Services for ADO.NET sample provided, which was very helpful. Some of the coding standards were not quite how I would have liked, but as a proof-of-concept it did the job.

After a few false starts we finally got it working in our trial application. There's one very interesting issue that we found: all your tables in your SyncAgent must be defined as BiDirectional, otherwise the SqlExpressClientSyncProvider sample class ignores them!

I was concerned that this might allow changes to download only tables, but if your server provider (which in our trial app is inside a WCF service) doesn't set the UpdateCommand or DeleteCommend then these changes are silently swallowed by the server. The client thinks the changes have been made server-side, but the server doesn't actually do anything.

This represents the final stage in proving our architecture to management, so now we'll be going full-steam ahead next week, with two new staff members starting on Monday: Nigel Spencer and Richard Hollon. That leaves only one person left for our "dream team" who will be starting in a few weeks.

3 comments:

David Gardiner said...

The dream team :-)

Ben Laan said...

Sounds great. Can't wait to start.

MatrixGoh said...

Update ApplyChanges method in ur SqlExpressClientSyncProvider.cs to method as below. I think this is a bug. I manage to did download only with the change.


public override SyncContext ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession)
{
foreach (SyncTableMetadata tableMetadata in groupMetadata.TablesMetadata)
{
if (tableMetadata.SyncDirection == SyncDirection.DownloadOnly || tableMetadata.SyncDirection == SyncDirection.Snapshot)
{
//This SyncDirection DownloadOnly/Snapshot is from a Client point of view. But our client is inturn a Server provider. Hence switch this to UploadOnly
tableMetadata.SyncDirection = SyncDirection.UploadOnly;
}
else if (tableMetadata.SyncDirection == SyncDirection.UploadOnly)
{
//This SyncDirection UploadOnly is from Client POV. But our client is inturn a Server provider. Hence switch this to DownloadOnly
tableMetadata.SyncDirection = SyncDirection.DownloadOnly;
}
}
SyncContext syncContext = _dbSyncProvider.ApplyChanges(groupMetadata, dataSet, syncSession);
foreach (SyncTableMetadata table in groupMetadata.TablesMetadata)
{
SetTableReceivedAnchor(table.TableName, groupMetadata.NewAnchor);
}
return syncContext;

}