/// <summary> /// Internal method called by the StoreConflict class in order to resolve a store conflict. This must be done /// because there must be some maintenance of the in-memory collections depending on the resolution of the conflict /// </summary> /// <param name="conflict">Conflict to resolve</param> /// <param name="resolutionAction">Resolution action.</param> internal void ResolveOfflineConflict(OfflineConflict conflict, SyncConflictResolutionAction resolutionAction) { using (saveSyncLock.LockObject()) { // Cache the modified entity, which may disappear depending on the resolution OfflineEntity visibleEntity = conflict.ModifiedEntity; // Respond to the resolution switch (resolutionAction) { case SyncConflictResolutionAction.AcceptModifiedEntity: conflict.ModifiedEntity.UpdateModifiedTickCount(); break; case SyncConflictResolutionAction.AcceptStoreEntity: cacheData.ResolveStoreConflictByRollback(conflict.ModifiedEntity); break; default: throw new ArgumentException("Invalid resolution action specified"); } // Cleanup pointers to conflicts everywhere. visibleEntity.OfflineConflict = null; offlineConflicts.Remove(conflict); // Clearing the c will prevent the resolution from being triggered again. conflict.ClearContext(); } }
public void ProcessedEntity(OfflineEntity entity) { string atomId = entity.ServiceMetadata.Id; OfflineEntityKey key = (OfflineEntityKey)entity.GetIdentity(); key.TypeName = entity.GetType().FullName; if (entity.IsTombstone) { if (String.IsNullOrEmpty(atomId)) { pkeySet.Add(key); } else { atomIdSet.Add(atomId); } } else { pkeySet.Add(key); if (!String.IsNullOrEmpty(atomId)) { atomIdSet.Add(atomId); } } }
public bool ContainsEntity(OfflineEntity entity) { // If the entity is a tombstone, use the atom id if (entity.IsTombstone) { if (String.IsNullOrEmpty(entity.ServiceMetadata.Id)) { // if it's a tombstone and the id is null, it means it is a delete of // a local insert that can be skipped, so we report it as already written return(true); } return(atomIdSet.Contains(entity.ServiceMetadata.Id)); } if (!String.IsNullOrEmpty(entity.ServiceMetadata.Id)) { return(atomIdSet.Contains(entity.ServiceMetadata.Id)); } OfflineEntityKey key = (OfflineEntityKey)entity.GetIdentity(); key.TypeName = entity.GetType().FullName; return(pkeySet.Contains(key)); }
/// <summary> /// Adds a error to the list of in-memory /// </summary> /// <param name="error"></param> /// <param name="context">Context for the conflict is being added</param> public void AddSyncError(SyncError error, WinEightContext context) { OfflineEntity entity = Collections[error.LiveEntity.GetType()].AddOrUpdateSyncEntity((OfflineEntity)error.LiveEntity); SyncError oldError = Collections[error.LiveEntity.GetType()].MapSyncError(entity, error, context); SyncErrors.Add(error); if (oldError != null) { ClearSyncError(oldError, context); } }
/// <summary> /// Adds a conflict to the list of in-memory /// </summary> /// <param name="conflict">Conflict to add</param> /// <param name="context">Context for which the conflict is being added</param> public void AddSyncConflict(SyncConflict conflict, WinEightContext context) { OfflineEntity entity = Collections[conflict.LiveEntity.GetType()].AddOrUpdateSyncEntity((OfflineEntity)conflict.LiveEntity); SyncConflict oldConflict = Collections[conflict.LiveEntity.GetType()].MapSyncConflict(entity, conflict, context); SyncConflicts.Add(conflict); if (oldConflict != null) { ClearSyncConflict(oldConflict, context); } }
/// <summary> /// Does reflection to copy the properties from another entity to this entity /// </summary> /// <param name="entity">Entity from which to copy properties</param> private void CopyEntityToThis(OfflineEntity entity) { IEnumerable <PropertyInfo> propInfos = GetEntityProperties(); object[] parameters = new object[] { }; foreach (PropertyInfo propInfo in propInfos) { propInfo.SetMethod.Invoke(this, new[] { propInfo.GetMethod.Invoke(entity, parameters) }); } CopyODataPropertiesToThis(entity); this.entityMetadata.IsTombstone = entity.entityMetadata.IsTombstone; }
/// <summary> /// Gets the original state of the entity at the time it was last Submitted. /// </summary> /// <returns>The original entity, if the entity has been modified, null otherwise.</returns> public OfflineEntity GetOriginal() { OfflineEntity org = null; lock (syncRoot) { if (this.EntityState == OfflineEntityState.Modified && this.original != null) { org = (OfflineEntity)Activator.CreateInstance(this.GetType()); FillEntityFromSnapshot(org); org.IsReadOnly = true; } } return(org); }
/// <summary> /// Copies the properties from the entity to the snapshot /// </summary> /// <param name="entity">Entity from which to copy properties</param> private OfflineEntitySnapshot GetSnapshotFromEntity(OfflineEntity entity) { OfflineEntitySnapshot snapshot = new OfflineEntitySnapshot(); IEnumerable <PropertyInfo> properties = GetEntityProperties(); // Copy data properties foreach (PropertyInfo property in properties) { object val = property.GetMethod.Invoke(entity, null); snapshot.Properties[property.Name] = val; } snapshot.TickCount = entity.TickCount; snapshot.EntityState = entity.EntityState; snapshot.Metadata = entity.ServiceMetadata.Clone(); return(snapshot); }
/// <summary> /// Uses the snapshot to fill the entity's properties /// </summary> /// <param name="entity">Entity to fill</param> internal void FillEntityFromSnapshot(OfflineEntity entity) { Type type = entity.GetType(); foreach (var property in original.Properties) { PropertyInfo propInfo = type.GetTypeInfo().GetDeclaredProperty(property.Key); // If propInfo is null, it's an internal property // that will be handled later if (propInfo != null) { propInfo.SetMethod.Invoke(entity, new[] { property.Value }); } } // Get the internal properties entity.entityMetadata = original.Metadata; entity.EntityState = original.EntityState; entity.TickCount = original.TickCount; }
/// <summary> /// Updates an entity from sync. /// </summary> /// <param name="entity">Entity with changes to update</param> /// <returns>Whether or not the entity is already modified</returns> internal void UpdateFromSync(OfflineEntity entity) { lock (syncRoot) { if (this.EntityState == OfflineEntityState.Modified) { OfflineEntitySnapshot snapshot = GetSnapshotFromEntity(entity); snapshot.IsTombstone = entity.IsTombstone; snapshot.TickCount = this.TickCount + 1; this.original = snapshot; } else { trackChanges = false; // Update properties CopyEntityToThis(entity); trackChanges = true; } } }
public abstract void ClearSyncError(OfflineEntity entity);
public abstract void ClearSyncConflict(OfflineEntity entity);
public abstract OfflineEntity AddOrUpdateSyncEntity(OfflineEntity entity, bool delayNotification);
/// <summary> /// Copies OData properties that don't need to be snapshoted /// </summary> /// <param name="entity">Entity from which to copy properties</param> private void CopyODataPropertiesToThis(OfflineEntity entity) { this.entityMetadata.Id = entity.entityMetadata.Id; this.entityMetadata.EditUri = entity.entityMetadata.EditUri; this.entityMetadata.ETag = entity.entityMetadata.ETag; }
/// <summary> /// Copies the properties from the entity to the snapshot /// </summary> /// <param name="entity">Entity from which to copy properties</param> private OfflineEntitySnapshot GetSnapshotFromEntity(OfflineEntity entity) { OfflineEntitySnapshot snapshot = new OfflineEntitySnapshot(); IEnumerable<PropertyInfo> properties = GetEntityProperties(); // Copy data properties foreach (PropertyInfo property in properties) { object val = property.GetMethod.Invoke(entity, null); snapshot.Properties[property.Name] = val; } snapshot.TickCount = entity.TickCount; snapshot.EntityState = entity.EntityState; snapshot.Metadata = entity.ServiceMetadata.Clone(); return snapshot; }
public abstract void AddSerializedEntity(OfflineEntity entity);
public abstract void ResolveConflictByRollback(OfflineEntity entity);
public abstract SyncError MapSyncError(OfflineEntity entity, SyncError error, WinEightContext context);
public abstract SyncConflict MapSyncConflict(OfflineEntity entity, SyncConflict conflict, WinEightContext context);
public abstract OfflineEntity AddOrUpdateSyncEntity(OfflineEntity entity);
/// <summary> /// Does reflection to copy the properties from another entity to this entity /// </summary> /// <param name="entity">Entity from which to copy properties</param> private void CopyEntityToThis(OfflineEntity entity) { IEnumerable<PropertyInfo> propInfos = GetEntityProperties(); object[] parameters = new object[] { }; foreach (PropertyInfo propInfo in propInfos) { propInfo.SetMethod.Invoke(this, new[] { propInfo.GetMethod.Invoke(entity, parameters) }); } CopyODataPropertiesToThis(entity); this.entityMetadata.IsTombstone = entity.entityMetadata.IsTombstone; }
public void AddSerializedLocalChange(OfflineEntity entity) { entity.EntityState = OfflineEntityState.Saved; Collections[entity.GetType()].AddSerializedEntity(entity); }
/// <summary> /// Method called by the context to resolve a conflict with StoreItemWins /// </summary> /// <param name="entity"></param> public void ResolveStoreConflictByRollback(OfflineEntity entity) { Type type = entity.GetType(); Collections[type].ResolveConflictByRollback(entity); }
public void AddSerializedDownloadItem(OfflineEntity entity) { entity.EntityState = OfflineEntityState.Unmodified; // Pass the entity to the collection Collections[entity.GetType()].AddOrUpdateSyncEntity(entity); }