Sync 4.0 Code: Fix for UploadChangesRequestProcesser.GetSyncWriterWithContents()
-
2011年9月12日 上午 12:58
With the release of the source code for Sync Framework 4.0 I've finally found the cause of a problem I've had since the release of the first private CTP mid last year. The cause of the problem has been related to the normalisation of the tables in my database. So the easiest example is one of 'clients' in my system. Clients can be one of 4 different types, all of which share a large number of common properties but they each have some specific properties that define their type. On normalising this concept you come out with an 'abstract' Client table with the common properties along with 4 'concrete' tables for the different types' specific data. From the Client table perspective the foreign key relationships to each of the 4 specific client tables is a 0..1 relationship. For my own personal sanity I name the foreign key in a table the same name as the primary key of the table it's linking to. So I'm using ClientID in the Client table and then each of the specific client tables has a ClientID to link back. But of course it makes sense that the ClientID in the specific tables is their primary key.
So with all that background the problem with the UploadChangesRequestProcesser.GetSyncWriterWithContents() method is that in order to determine whether any primary key clashes have occurred it adds a primaryKey string (being the name of the primary key field and its value) as the key to a dictionary. Then it checks future primaryKey strings against that dictionary to determine whether a clash has occurred. That of course falls down when you send a Client entity with ClientID='x' and also send an IndividualClient entity with ClientID='x'. This isn't actually a primary key clash because there is only one ClientID 'x' in the Client table and one ClientID 'x' in the IndividualClient table.
I'm proposing the following change to the UploadChangesRequestProcesser.GetSyncWriterWithContents() method to handle this class of error in a better way:
private SyncWriter GetSyncWriterWithContents() { var conflictEntryKeys = new List<string>(); var errorEntryKeys = new List<string>(); var primaryKeyToIncomingEntitiesMapping = new Dictionary<string, IOfflineEntity>(); // Save the mapping between entity PK string -> entity foreach (var entity in _incomingEntities) { string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity); string entityType = entity.GetType().ToString(); string key = entityType + ":" + primaryKey; if (primaryKeyToIncomingEntitiesMapping.ContainsKey(key)) { throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest); } primaryKeyToIncomingEntitiesMapping.Add(key, entity); } if (_rejectedEntities != null) { foreach (var entity in _rejectedEntities.Keys) { string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity); string entityType = entity.GetType().ToString(); string key = entityType + ":" + primaryKey; if (primaryKeyToIncomingEntitiesMapping.ContainsKey(key)) { throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest); } primaryKeyToIncomingEntitiesMapping.Add(key, entity); } }
Fairly simple and the primaryKeyToIncomingEntitiesMapping dictionary isn't used beyond that first checking part of the method so there shouldn't be any adverse effects to the general code base. Obviously you could inline the key creation but I just wanted to make it clearer here.
所有回覆
-
2011年9月12日 上午 01:06I'll just add here that in the long run I'd like to alter the SyncServiceUtil to be able to generate only the concrete client entities (joining the concrete table with the abstract table to return a single entity) but don't have time to look at that just at the moment.
-
2012年6月11日 上午 08:42
Hi,
how to edit this method ??
Microsoft.Synchronization.Services - sourcecode available ?
Navin
-
2012年6月11日 上午 08:48版主
you have to be more specific on which assembly (dll) are you referring to... if you're referring to the Sync Toolkit, the source code is part of the download.
also, you might want to open another thread as its completely different to what the original poster has intended for this thread.
- 已編輯 JuneTMVP, Moderator 2012年6月11日 上午 08:49
-
2012年6月27日 下午 04:42We have this exact same scenario with one "abstract" work order table and several "concrete" work order tables (eg WorkOrder_Maintenance, WorkOrder_Support). They all have WorkOrderId as their primary key field. This is very helpful. Thanks.