Exemplo n.º 1
0
        private JObject InvokeSerializeDataToJson(Type classType, object data, SyncConfiguration.SchemaInfo schemaInfo, object transaction, OperationType operationType, string synchronizationId, Dictionary <string, object> customInfo)
        {
            string json = SerializeDataToJson(classType, data, transaction, operationType, synchronizationId, customInfo);

            if (string.IsNullOrEmpty(json))
            {
                throw new SyncEngineConstraintException($"{nameof(SerializeDataToJson)} must not return null or empty string");
            }
            JObject jObject = null;

            try
            {
                jObject = JsonConvert.DeserializeObject <JObject>(json);
            }
            catch (Exception e)
            {
                throw new SyncEngineConstraintException($"The returned value from {nameof(SerializeDataToJson)} cannot be parsed as JSON Object (JObject). Error: {e.Message}. Returned Value: {json}");
            }
            if (!jObject.ContainsKey(schemaInfo.PropertyInfoId.Name))
            {
                throw new SyncEngineConstraintException($"The parsed JSON Object (JObject) does not contain key: {schemaInfo.PropertyInfoId.Name} (SyncProperty Id)");
            }
            if (!jObject.ContainsKey(schemaInfo.PropertyInfoLastUpdated.Name))
            {
                throw new SyncEngineConstraintException($"The parsed JSON Object (JObject) does not contain key: {schemaInfo.PropertyInfoLastUpdated.Name} (SyncProperty LastUpdated)");
            }
            if (!jObject.ContainsKey(schemaInfo.PropertyInfoDeleted.Name))
            {
                throw new SyncEngineConstraintException($"The parsed JSON Object (JObject) does not contain key: {schemaInfo.PropertyInfoDeleted.Name} (SyncProperty Deleted)");
            }
            return(jObject);
        }
Exemplo n.º 2
0
        internal void ProvisionExistingData(List <string> log, long timeStamp, object transaction, OperationType operationType, string synchronizationId, Dictionary <string, object> customInfo)
        {
            if (log == null)
            {
                log = new List <string>();
            }

            log.Add("Provisioning All Existing Local Data with the acquired TimeStamp...");
            log.Add($"SyncTypes Count: {SyncConfiguration.SyncTypes.Count}");
            for (int i = 0; i < SyncConfiguration.SyncTypes.Count; i++)
            {
                Type syncType = SyncConfiguration.SyncTypes[i];
                log.Add($"Processing Type: {syncType.Name} ({i + 1} of {SyncConfiguration.SyncTypes.Count})");
                int dataCount = 0;
                SyncConfiguration.SchemaInfo schemaInfo = GetSchemaInfo(SyncConfiguration, syncType);
                IQueryable queryable = InvokeGetQueryable(syncType, transaction, operationType, synchronizationId, customInfo);
                queryable = queryable.Where($"{schemaInfo.PropertyInfoDatabaseInstanceId.Name} = null || {schemaInfo.PropertyInfoDatabaseInstanceId.Name} = \"\"");
                System.Collections.IEnumerator enumerator = queryable.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    dataCount += 1;
                    object data = enumerator.Current;
                    data.GetType().GetProperty(schemaInfo.PropertyInfoDatabaseInstanceId.Name).SetValue(data, null);
                    data.GetType().GetProperty(schemaInfo.PropertyInfoLastUpdated.Name).SetValue(data, timeStamp);
                    PersistData(syncType, data, false, transaction, operationType, synchronizationId, customInfo);
                }
                log.Add($"Type: {syncType.Name} Processed. Provisioned Data Count: {dataCount}");
            }
        }
Exemplo n.º 3
0
 public void HookPreInsertOrUpdateGlobalTimeStamp(object data)
 {
     if (data == null)
     {
         throw new NullReferenceException(nameof(data));
     }
     SyncConfiguration.SchemaInfo schemaInfo = GetSchemaInfo(SyncConfiguration, data.GetType());
     if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
     {
         long nowTicks = GetNowTicks();
         if (!IsServerEngine())
         {
             long lastSync = GetClientLastSync();
             if (nowTicks <= lastSync && !SyncConfiguration.SyncConfigurationOptions.GlobalTimeStampAllowHooksToUpdateWithOlderSystemDateTime)
             {
                 throw new SyncEngineConstraintException("System Date and Time is older than the lastSync value");
             }
         }
         data.GetType().GetProperty(schemaInfo.PropertyInfoLastUpdated.Name).SetValue(data, nowTicks);
     }
     else
     {
         throw new SyncEngineConstraintException($"Mismatch Hook Method for {SyncConfiguration.TimeStampStrategy}");
     }
 }
Exemplo n.º 4
0
            internal static SyncLogData FromJObject(JObject jObject, Type syncType, SyncConfiguration.SchemaInfo schemaInfo)
            {
                SyncLogData syncLogData = new SyncLogData();

                syncLogData.TypeName    = syncType.Name;
                syncLogData.Id          = Convert.ToString(jObject[schemaInfo.PropertyInfoId.Name].Value <object>());
                syncLogData.LastUpdated = jObject[schemaInfo.PropertyInfoLastUpdated.Name].Value <long>();
                syncLogData.Deleted     = jObject[schemaInfo.PropertyInfoDeleted.Name].Value <long?>();
                syncLogData.JsonData    = jObject.ToString();
                if (schemaInfo.PropertyInfoFriendlyId != null)
                {
                    syncLogData.FriendlyId = jObject[schemaInfo.PropertyInfoFriendlyId.Name].Value <string>();
                }
                return(syncLogData);
            }
Exemplo n.º 5
0
 public void HookPreInsertOrUpdateDatabaseTimeStamp(object data, object transaction, string synchronizationId, Dictionary <string, object> customInfo)
 {
     if (data == null)
     {
         throw new NullReferenceException(nameof(data));
     }
     SyncConfiguration.SchemaInfo schemaInfo = GetSchemaInfo(SyncConfiguration, data.GetType());
     if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
     {
         long timeStamp = InvokeGetNextTimeStamp();
         UpdateLocalKnowledgeTimeStamp(timeStamp, synchronizationId, customInfo, null, transaction);
         data.GetType().GetProperty(schemaInfo.PropertyInfoDatabaseInstanceId.Name).SetValue(data, null);
         data.GetType().GetProperty(schemaInfo.PropertyInfoLastUpdated.Name).SetValue(data, timeStamp);
     }
     else
     {
         throw new SyncEngineConstraintException($"Mismatch Hook Method for {SyncConfiguration.TimeStampStrategy}");
     }
 }
Exemplo n.º 6
0
        private object InvokeDeserializeJsonToExistingData(Type classType, JObject jObject, object data, object localId, object transaction, OperationType operationType, ConflictType conflictType, string synchronizationId, Dictionary <string, object> customInfo, SyncConfiguration.SchemaInfo localSchemaInfo)
        {
            object existingData = DeserializeJsonToExistingData(classType, jObject, data, transaction, operationType, conflictType, synchronizationId, customInfo);

            if (conflictType != ConflictType.NoConflict && existingData == null)
            {
                return(null);
            }
            if (existingData == null)
            {
                throw new SyncEngineConstraintException($"{nameof(DeserializeJsonToExistingData)} must not return null for {nameof(conflictType)} equals to {conflictType.ToString()}");
            }
            if (existingData.GetType().FullName != classType.FullName)
            {
                throw new SyncEngineConstraintException($"Expected returned Type: {classType.FullName} during {nameof(DeserializeJsonToExistingData)}, but Type: {existingData.GetType().FullName} is returned instead.");
            }
            object existingDataId = classType.GetProperty(localSchemaInfo.PropertyInfoId.Name).GetValue(existingData);

            if (!existingDataId.Equals(localId))
            {
                throw new SyncEngineConstraintException($"The returned Object Id ({existingDataId}) is different than the existing data Id: {localId}");
            }
            return(existingData);
        }
Exemplo n.º 7
0
        internal (JObject typeChanges, int typeChangesCount, long maxTimeStamp, List <SyncLog.SyncLogData> logChanges) GetTypeChanges(long?lastSync, Type syncType, string synchronizationId, Dictionary <string, object> customInfo, List <object> appliedIds)
        {
            if (string.IsNullOrEmpty(synchronizationId))
            {
                throw new NullReferenceException(nameof(synchronizationId));
            }
            if (lastSync == null)
            {
                lastSync = GetMinValueTicks();
            }
            if (customInfo == null)
            {
                customInfo = new Dictionary <string, object>();
            }
            long maxTimeStamp = GetMinValueTicks();
            List <SyncLog.SyncLogData> logChanges = new List <SyncLog.SyncLogData>();

            SyncConfiguration.SchemaInfo schemaInfo = GetSchemaInfo(SyncConfiguration, syncType);
            JObject typeChanges = null;
            JArray  datas       = new JArray();

            OperationType operationType = OperationType.GetChanges;
            object        transaction   = StartTransaction(syncType, operationType, synchronizationId, customInfo);

            try
            {
                IQueryable queryable = InvokeGetQueryable(syncType, transaction, operationType, synchronizationId, customInfo);
                if (appliedIds == null || appliedIds.Count == 0)
                {
                    queryable = queryable.Where($"{schemaInfo.PropertyInfoLastUpdated.Name} > @0 || ({schemaInfo.PropertyInfoDeleted.Name} != null && {schemaInfo.PropertyInfoDeleted.Name} > @1)", lastSync.Value, lastSync);
                }
                else
                {
                    Type       typeId           = Type.GetType(schemaInfo.PropertyInfoId.PropertyType, true);
                    MethodInfo miCast           = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(typeId);
                    object     appliedIdsTypeId = miCast.Invoke(appliedIds, new object[] { appliedIds });
                    queryable = queryable.Where($"({schemaInfo.PropertyInfoLastUpdated.Name} > @0 || ({schemaInfo.PropertyInfoDeleted.Name} != null && {schemaInfo.PropertyInfoDeleted.Name} > @1)) && !(@2.Contains({schemaInfo.PropertyInfoId.Name}))", lastSync.Value, lastSync, appliedIdsTypeId);
                }
                queryable = queryable.OrderBy($"{schemaInfo.PropertyInfoDeleted.Name}, {schemaInfo.PropertyInfoLastUpdated.Name}");
                List <dynamic> dynamicDatas = queryable.ToDynamicList();
                if (dynamicDatas.Count > 0)
                {
                    typeChanges = new JObject();
                    typeChanges[nameof(syncType)]   = syncType.Name;
                    typeChanges[nameof(schemaInfo)] = schemaInfo.ToJObject();
                    foreach (dynamic dynamicData in dynamicDatas)
                    {
                        JObject jObjectData = InvokeSerializeDataToJson(syncType, dynamicData, schemaInfo, transaction, operationType, synchronizationId, customInfo);
                        datas.Add(jObjectData);
                        long lastUpdated = jObjectData[schemaInfo.PropertyInfoLastUpdated.Name].Value <long>();
                        long?deleted     = jObjectData[schemaInfo.PropertyInfoDeleted.Name].Value <long?>();
                        if (lastUpdated > maxTimeStamp)
                        {
                            maxTimeStamp = lastUpdated;
                        }
                        if (deleted.HasValue && deleted.Value > maxTimeStamp)
                        {
                            maxTimeStamp = deleted.Value;
                        }
                        logChanges.Add(SyncLog.SyncLogData.FromJObject(jObjectData, syncType, schemaInfo));
                    }
                    typeChanges[nameof(datas)] = datas;
                }
                CommitTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
            }
            catch (Exception)
            {
                RollbackTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
                throw;
            }
            finally
            {
                EndTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
            }
            return(typeChanges, datas.Count, maxTimeStamp, logChanges);
        }
Exemplo n.º 8
0
        internal (Type localSyncType, List <object> appliedIds, List <object> deletedIds) ApplyTypeChanges(List <string> log, List <SyncLog.SyncLogData> inserts, List <SyncLog.SyncLogData> updates, List <SyncLog.SyncLogData> deletes, List <SyncLog.SyncLogConflict> conflicts, JObject typeChanges, string synchronizationId, Dictionary <string, object> customInfo, string sourceDatabaseInstanceId, string destinationDatabaseInstanceId)
        {
            if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
            {
                if (!string.IsNullOrEmpty(sourceDatabaseInstanceId) || !string.IsNullOrEmpty(destinationDatabaseInstanceId))
                {
                    throw new Exception($"{SyncConfiguration.TimeStampStrategy.ToString()} must have {nameof(sourceDatabaseInstanceId)} and {nameof(destinationDatabaseInstanceId)} equals to null");
                }
            }
            else if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
            {
                if (string.IsNullOrEmpty(sourceDatabaseInstanceId) || string.IsNullOrEmpty(destinationDatabaseInstanceId))
                {
                    throw new Exception($"{SyncConfiguration.TimeStampStrategy.ToString()} must have {nameof(sourceDatabaseInstanceId)} and {nameof(destinationDatabaseInstanceId)} both not null");
                }
            }
            else
            {
                throw new NotImplementedException(SyncConfiguration.TimeStampStrategy.ToString());
            }

            List <object>             appliedIds = new List <object>();
            List <object>             deletedIds = new List <object>();
            Dictionary <string, long> databaseInstanceMaxTimeStamps = new Dictionary <string, long>();

            if (inserts == null)
            {
                inserts = new List <SyncLog.SyncLogData>();
            }
            if (updates == null)
            {
                updates = new List <SyncLog.SyncLogData>();
            }
            if (deletes == null)
            {
                deletes = new List <SyncLog.SyncLogData>();
            }
            if (conflicts == null)
            {
                conflicts = new List <SyncLog.SyncLogConflict>();
            }
            string  syncTypeName      = typeChanges["syncType"].Value <string>();
            JObject jObjectSchemaInfo = typeChanges["schemaInfo"].Value <JObject>();

            SyncConfiguration.SchemaInfo schemaInfo = SyncConfiguration.SchemaInfo.FromJObject(jObjectSchemaInfo);
            string localSyncTypeName = syncTypeName;

            if (!string.IsNullOrEmpty(schemaInfo.SyncSchemaAttribute.MapToClassName))
            {
                localSyncTypeName = schemaInfo.SyncSchemaAttribute.MapToClassName;
            }
            Type localSyncType = SyncConfiguration.SyncTypes.Where(w => w.Name == localSyncTypeName).FirstOrDefault();

            if (localSyncType == null)
            {
                throw new SyncEngineConstraintException($"Unable to find SyncType: {localSyncTypeName} in SyncConfiguration");
            }
            SyncConfiguration.SchemaInfo localSchemaInfo = GetSchemaInfo(SyncConfiguration, localSyncType);

            OperationType operationType = OperationType.ApplyChanges;
            object        transaction   = StartTransaction(localSyncType, operationType, synchronizationId, customInfo);

            try
            {
                IQueryable queryable = InvokeGetQueryable(localSyncType, transaction, operationType, synchronizationId, customInfo);
                JArray     datas     = typeChanges["datas"].Value <JArray>();
                log.Add($"Data Count: {datas.Count}");
                for (int i = 0; i < datas.Count; i++)
                {
                    JObject jObjectData = datas[i].Value <JObject>();
                    JValue  id          = jObjectData[schemaInfo.PropertyInfoId.Name].Value <JValue>();
                    long    lastUpdated = jObjectData[schemaInfo.PropertyInfoLastUpdated.Name].Value <long>();

                    long?  deletedGlobalTimeStamp   = null;
                    bool   deletedDatabaseTimeStamp = false;
                    string databaseInstanceId       = null;
                    if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
                    {
                        deletedGlobalTimeStamp = jObjectData[schemaInfo.PropertyInfoDeleted.Name].Value <long?>();
                    }
                    if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                    {
                        deletedDatabaseTimeStamp = jObjectData[schemaInfo.PropertyInfoDeleted.Name].Value <bool>();
                        databaseInstanceId       = jObjectData[schemaInfo.PropertyInfoDatabaseInstanceId.Name].Value <string>();
                    }

                    object  localId     = TransformIdType(localSyncType, id, transaction, operationType, synchronizationId, customInfo);
                    dynamic dynamicData = queryable.Where($"{localSchemaInfo.PropertyInfoId.Name} == @0", localId).FirstOrDefault();
                    object  localData   = (object)dynamicData;

                    if (localData == null)
                    {
                        object newData = InvokeDeserializeJsonToNewData(localSyncType, jObjectData, transaction, operationType, synchronizationId, customInfo);
                        newData.GetType().GetProperty(localSchemaInfo.PropertyInfoId.Name).SetValue(newData, localId);
                        newData.GetType().GetProperty(localSchemaInfo.PropertyInfoLastUpdated.Name).SetValue(newData, lastUpdated);

                        if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
                        {
                            newData.GetType().GetProperty(localSchemaInfo.PropertyInfoDeleted.Name).SetValue(newData, deletedGlobalTimeStamp);
                        }
                        if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                        {
                            newData.GetType().GetProperty(localSchemaInfo.PropertyInfoDeleted.Name).SetValue(newData, deletedDatabaseTimeStamp);
                            newData.GetType().GetProperty(localSchemaInfo.PropertyInfoDatabaseInstanceId.Name).SetValue(newData, GetCorrectDatabaseInstanceId(databaseInstanceId, sourceDatabaseInstanceId, destinationDatabaseInstanceId, databaseInstanceMaxTimeStamps, lastUpdated));
                        }

                        PersistData(localSyncType, newData, true, transaction, operationType, synchronizationId, customInfo);
                        if (!appliedIds.Contains(localId))
                        {
                            appliedIds.Add(localId);
                        }
                        inserts.Add(SyncLog.SyncLogData.FromJObject(InvokeSerializeDataToJson(localSyncType, newData, localSchemaInfo, transaction, operationType, synchronizationId, customInfo), localSyncType, localSchemaInfo));
                    }
                    else
                    {
                        bool isDeleted = false;
                        if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
                        {
                            if (deletedGlobalTimeStamp != null)
                            {
                                isDeleted = true;
                            }
                        }
                        if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                        {
                            if (deletedDatabaseTimeStamp)
                            {
                                isDeleted = true;
                            }
                        }

                        if (!isDeleted)
                        {
                            ConflictType updateConflictType = ConflictType.NoConflict;
                            long         localLastUpdated   = (long)localData.GetType().GetProperty(localSchemaInfo.PropertyInfoLastUpdated.Name).GetValue(localData);
                            if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
                            {
                                if (localLastUpdated > lastUpdated)
                                {
                                    updateConflictType = ConflictType.ExistingDataIsNewerThanIncomingData;
                                }
                            }
                            if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                            {
                                string localDatabaseInstanceId   = (string)localData.GetType().GetProperty(localSchemaInfo.PropertyInfoDatabaseInstanceId.Name).GetValue(localData);
                                string correctDatabaseInstanceId = GetCorrectDatabaseInstanceId(databaseInstanceId, sourceDatabaseInstanceId, destinationDatabaseInstanceId, null, 0);
                                if (localDatabaseInstanceId == correctDatabaseInstanceId)
                                {
                                    if (localLastUpdated > lastUpdated)
                                    {
                                        updateConflictType = ConflictType.ExistingDataIsNewerThanIncomingData;
                                    }
                                }
                                else
                                {
                                    updateConflictType = ConflictType.ExistingDataIsUpdatedByDifferentDatabaseInstanceId;
                                }
                            }

                            object existingData = InvokeDeserializeJsonToExistingData(localSyncType, jObjectData, localData, localId, transaction, operationType, updateConflictType, synchronizationId, customInfo, localSchemaInfo);
                            if (existingData == null && updateConflictType == ConflictType.NoConflict)
                            {
                                throw new SyncEngineConstraintException($"{nameof(DeserializeJsonToExistingData)} must not return null for conflictType equals to {ConflictType.NoConflict.ToString()}");
                            }
                            if (existingData != null)
                            {
                                existingData.GetType().GetProperty(localSchemaInfo.PropertyInfoLastUpdated.Name).SetValue(existingData, lastUpdated);
                                if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                                {
                                    existingData.GetType().GetProperty(localSchemaInfo.PropertyInfoDatabaseInstanceId.Name).SetValue(existingData, GetCorrectDatabaseInstanceId(databaseInstanceId, sourceDatabaseInstanceId, destinationDatabaseInstanceId, databaseInstanceMaxTimeStamps, lastUpdated));
                                }
                                PersistData(localSyncType, existingData, false, transaction, operationType, synchronizationId, customInfo);
                                if (!appliedIds.Contains(localId))
                                {
                                    appliedIds.Add(localId);
                                }
                                updates.Add(SyncLog.SyncLogData.FromJObject(InvokeSerializeDataToJson(localSyncType, existingData, localSchemaInfo, transaction, operationType, synchronizationId, customInfo), localSyncType, localSchemaInfo));
                            }
                            else
                            {
                                log.Add($"CONFLICT Detected: {updateConflictType.ToString()}. Id: {id}");
                                conflicts.Add(new SyncLog.SyncLogConflict(updateConflictType, SyncLog.SyncLogData.FromJObject(jObjectData, localSyncType, schemaInfo)));
                            }
                        }
                        else
                        {
                            object existingData = InvokeDeserializeJsonToExistingData(localSyncType, jObjectData, localData, localId, transaction, operationType, ConflictType.NoConflict, synchronizationId, customInfo, localSchemaInfo);

                            if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.GlobalTimeStamp)
                            {
                                existingData.GetType().GetProperty(localSchemaInfo.PropertyInfoDeleted.Name).SetValue(existingData, deletedGlobalTimeStamp);
                            }
                            if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                            {
                                existingData.GetType().GetProperty(localSchemaInfo.PropertyInfoDeleted.Name).SetValue(existingData, deletedDatabaseTimeStamp);
                                existingData.GetType().GetProperty(localSchemaInfo.PropertyInfoDatabaseInstanceId.Name).SetValue(existingData, GetCorrectDatabaseInstanceId(databaseInstanceId, sourceDatabaseInstanceId, destinationDatabaseInstanceId, databaseInstanceMaxTimeStamps, lastUpdated));
                            }

                            PersistData(localSyncType, existingData, false, transaction, operationType, synchronizationId, customInfo);
                            if (!appliedIds.Contains(localId))
                            {
                                appliedIds.Add(localId);
                            }
                            if (!deletedIds.Contains(localId))
                            {
                                deletedIds.Add(localId);
                            }
                            deletes.Add(SyncLog.SyncLogData.FromJObject(InvokeSerializeDataToJson(localSyncType, existingData, localSchemaInfo, transaction, operationType, synchronizationId, customInfo), localSyncType, localSchemaInfo));
                        }
                    }
                }
                if (SyncConfiguration.TimeStampStrategy == SyncConfiguration.TimeStampStrategyEnum.DatabaseTimeStamp)
                {
                    foreach (var item in databaseInstanceMaxTimeStamps)
                    {
                        KnowledgeInfo knowledgeInfo = GetAllKnowledgeInfos(synchronizationId, customInfo).Where(w => w.DatabaseInstanceId == item.Key).FirstOrDefault();
                        if (knowledgeInfo != null && knowledgeInfo.MaxTimeStamp > item.Value)
                        {
                            continue;
                        }
                        if (knowledgeInfo == null && item.Key == destinationDatabaseInstanceId)
                        {
                            throw new SyncEngineConstraintException("Unexpected Knowledge Info State on Destination. Destination is not provisioned yet.");
                        }
                        if (knowledgeInfo == null)
                        {
                            knowledgeInfo = new KnowledgeInfo()
                            {
                                DatabaseInstanceId = item.Key,
                                IsLocal            = false
                            };
                        }
                        knowledgeInfo.MaxTimeStamp = item.Value;
                        CreateOrUpdateKnowledgeInfo(knowledgeInfo, synchronizationId, customInfo);
                    }
                }
                CommitTransaction(localSyncType, transaction, operationType, synchronizationId, customInfo);
            }
            catch (Exception)
            {
                RollbackTransaction(localSyncType, transaction, operationType, synchronizationId, customInfo);
                throw;
            }
            finally
            {
                EndTransaction(localSyncType, transaction, operationType, synchronizationId, customInfo);
            }

            return(localSyncType, appliedIds, deletedIds);
        }
Exemplo n.º 9
0
        internal (JObject typeChanges, int typeChangesCount, List <SyncLog.SyncLogData> logChanges) GetTypeChangesByKnowledge(Type syncType, string localDatabaseInstanceId, List <KnowledgeInfo> remoteKnowledgeInfos, string synchronizationId, Dictionary <string, object> customInfo)
        {
            if (string.IsNullOrEmpty(synchronizationId))
            {
                throw new NullReferenceException(nameof(synchronizationId));
            }
            if (customInfo == null)
            {
                customInfo = new Dictionary <string, object>();
            }

            List <SyncLog.SyncLogData> logChanges = new List <SyncLog.SyncLogData>();

            SyncConfiguration.SchemaInfo schemaInfo = GetSchemaInfo(SyncConfiguration, syncType);
            JObject typeChanges = null;
            JArray  datas       = new JArray();

            OperationType operationType = OperationType.GetChanges;
            object        transaction   = StartTransaction(syncType, operationType, synchronizationId, customInfo);

            try
            {
                IQueryable queryable = InvokeGetQueryable(syncType, transaction, operationType, synchronizationId, customInfo);

                string predicate        = "";
                string predicateUnknown = "";
                for (int i = 0; i < remoteKnowledgeInfos.Count; i++)
                {
                    KnowledgeInfo info = remoteKnowledgeInfos[i];

                    string knownDatabaseInstanceId = null;
                    if (info.DatabaseInstanceId == localDatabaseInstanceId)
                    {
                        knownDatabaseInstanceId = "null";
                    }
                    else
                    {
                        knownDatabaseInstanceId = $"\"{info.DatabaseInstanceId}\"";
                    }

                    if (!string.IsNullOrEmpty(predicate))
                    {
                        predicate += " || ";
                    }
                    predicate += "(";
                    predicate += $"{schemaInfo.PropertyInfoDatabaseInstanceId.Name} = {knownDatabaseInstanceId} ";
                    predicate += $" && {schemaInfo.PropertyInfoLastUpdated.Name} > {info.MaxTimeStamp}";
                    predicate += ")";

                    if (!string.IsNullOrEmpty(predicateUnknown))
                    {
                        predicateUnknown += " && ";
                    }
                    predicateUnknown += $"{schemaInfo.PropertyInfoDatabaseInstanceId.Name} != {knownDatabaseInstanceId}";
                }
                queryable = queryable.Where($"{predicate} || ({predicateUnknown})");
                queryable = queryable.OrderBy($"{schemaInfo.PropertyInfoDeleted.Name}, {schemaInfo.PropertyInfoLastUpdated.Name}");
                List <dynamic> dynamicDatas = queryable.ToDynamicList();
                if (dynamicDatas.Count > 0)
                {
                    typeChanges = new JObject();
                    typeChanges[nameof(syncType)]   = syncType.Name;
                    typeChanges[nameof(schemaInfo)] = schemaInfo.ToJObject();
                    foreach (dynamic dynamicData in dynamicDatas)
                    {
                        JObject jObjectData = InvokeSerializeDataToJson(syncType, dynamicData, schemaInfo, transaction, operationType, synchronizationId, customInfo);
                        datas.Add(jObjectData);
                        logChanges.Add(SyncLog.SyncLogData.FromJObject(jObjectData, syncType, schemaInfo));
                    }
                    typeChanges[nameof(datas)] = datas;
                }
                CommitTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
            }
            catch (Exception)
            {
                RollbackTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
                throw;
            }
            finally
            {
                EndTransaction(syncType, transaction, operationType, synchronizationId, customInfo);
            }
            return(typeChanges, datas.Count, logChanges);
        }