Additional Q&A on the Visual Studio Orcas Sync Designer
Q: Why does the Orcas Feb CTP Typed DataSet designer not work on Vista?
A: Visual Studio Orcas is not yet fully compatible with Vista. In the Feb CTP there are several issues with something we call "red bits". These are changes to the runtime that shipped in .NET 3.0 which shipped with Vista. For our own internal testing, we do have fixes allowing us to test on Vista and all the scenarios are working. However, due to the way the dlls are signed and shipped in Vista, and the time crunch we're working under, we weren't able to get the work done in such a way that we could service a Vista box that had the Feb CTP installed. This was a very tough decision as we do not want to set the expectation that Visual Studio Orcas won't be Vista compatible. But, it was felt more important to make sure that anything we ship, including the CTP must be serviceable. As we all know, we're working on to maintain our schedule, and since CTP's are not meant to reflect the final quality, it was determined to ship the Feb CTP without full Vista support. As those that have seen my demos, we do have Vista working, and we will have full support for Vista. I believe, but not sure, that B1 will be fully Vista compatible. So, for now, if you're using Vista, the Feb CTP should be run in a VPC. In general, it's not a bad practice anyway.
Q: Will the Sync Designer generate time based sync?
A: This feature was unfortunately cut. We had some great designs, and even some prototypes that I've demo'd previously. However, we just didn't have the time to do all the background task, network resource detection, and timer work. Rather than hack something together we didn't have time to fully design, dev and test, we've had to cut this feature altogether. Of course this doesn't mean developers aren't smart enough to do this work with a combination of the BackgroundWorker, Timer and Network events. It just means we don't have a checkbox to do all the work automatically. We will have samples on how to do this, and we're in discussion with Patterns & Practices group on filling these gaps ‘till we have fully integrated runtime components that make this "just work".
Q: Will tombstone records be automatically cleaned up?
A: This was another cut we made in the sync designer with Visual Studio Orcas. Tombstone records are how we track deletes. If you sync on Monday and get the full product catalog, and then sync again on Wednesday, how can the server answer the question of "what was deleted". There are many ways to handle this. You can mark the main record with a status of Active = False, or you can physically delete the row and in the Deletion Trigger copy the PK to a [Table]_Tombstone record. The later is what the Visual Studio Orcas Sync Designer does. We had planned to create a Scheduled Task to automatically purge these deleted records, but since SQL Server Express doesn't have the Agent, we felt this was going to be too confusing. We also expect developers will do some additional work between their development and production boxes, so for now we punted this. We're not yet talking in detail about our SQL Server Katmai release, but you can expect we're doing some cool things here. So, for now, you'll have to create a scheduled task to purge the tombstone records that are say older than 30 days. Stay tuned, and we'll have more exciting things to discuss about the upcoming Katmai rlease.
Q: How do I get my cached tables to be synchronized in a single transaction?
A: The Orcas Sync Designer is focused on download scenarios. You can absolutely extend the sync designer generated code to do uploads as well, and in fact we even generate the upload SyncAdapter commands. For download only scenarios it was felt we should keep things simple by default and enable the ability to easily recover from dropped connections. So, by default, the Sync Designer synchronizes each table individually. As one table is finished, the next table is synchronized. This means if table 1 finishes, and the connection drops during table 2, that the next time a sync occurs, Table1 is likely already complete. To put all the tables in a single transaction, expand the [advanced] expando button and choose the sync all tables in a single transaction option.
For the Feb CTP, the Sync Designer generated a SyncGroup for each table. This wasn't necessary as the SyncAgent knows to place each in it's own SyncGroup when one isn't specified. This has since been changed so you'll only get a SyncGroup when placing all in a single transaction.
Q: Once all the tables are placed in a single transaction, how do I control the order the tables are updated to handle parent/child relationships?
A: The Sync Runtime will apply inserts, updates and deletes based on the order of the SyncTables and SyncAdapters in their respective collections. This isn't fully implemented in the Orcas Feb CTP, or the Jan Sync CTP. However, we do now have that updated internally and will be releasing it soon in the CTP. In an upcoming screen cast you'll see the current updates to the Sync Designer, including the ability to move items in the collection up and down.
Q: Does the sync runtime create relationships locally within SQLce?
A: No, I touched on this here: http://blogs.msdn.com/stevelasker/default.aspx#constraints
Q: Does the sync runtime work with server side identities for PK's?
A: No, no, and maybe. In general, despite the fact that many of our own samples depend on the Identity feature to manage the primary key, identities are an overall poor design. Building offline apps is only the extreme of the problem. How do you create a new row on the client, assign it a primary key when the client won't actually know the PK until it posts it to the server? However, the problem exists in "connected" stacks as well. Say you're creating a Order with a collection of OrderDetails. The standard model is to have the OrderDetails table reference the PK of it's parent, than add another sub key, say line number. You can't actually create the OrderItem records until the Order record is posted first. This creates complications for connected development. Sure, you can use the @@scope_identity value, but you still have to do a bunch of updates. Sure, you can wrap this in a sproc, but it's still a PITA. Now, consider you're building a high availability system. You have multiple server nodes managing the creation of data. Who owns the master identity range? We see this in rollup scenarios all the time. Each branch maintains their own data. Each uses identities. When the data is rolled up to corporate, you have collisions, requiring you to add the branch id to the corporate database. Now, you could partition the identity values, which is what we do in Merge Replication, but now we've introduced additional problems. Prior to joining Microsoft we deployed many mobile applications. If a person is in the field, using Merge Replication, and is working with their partition of IDs, what happens when they use them up? They have to re-synchronize with the server to get a new allocation, which they may not be able to do at the time they've run out. So, the app is dead. Another client doesn't use up their allocation and leaves "holes" in the server.
So, what's the solution? There are two ways, the simple but not always the most efficient, and the complex. The simple is to simply use GUIDs. SQL Server and SQLce both have UniqueIdentifier data types. You can either set the IsRowGuid property, or create your own GUID with Guid.NewGuid(). The other is to create your own hashing. Each client is given a hash when the initially connect to the server. They then create incremental counters, possibly even with Identity within their hash. Now when you push up the new values, voila, no conflicts. If you still want incremental counters, say for that single, simple OrderId, you could still use the Identity feature, just don't make it the primary key. You upload a new order from the client. The client assigned a primary key using it's hash. When that order is uploaded to the server, the server applies the identity value to the non-pk column. The update is then brought back down to the client. Life is good.